Hệ thống xếp lịch học tín chỉ cho sinh viên CNTT trên PHP & MySQL
111.135 lượt xem;
- incCommon.php
- project /
1 <?php
2
3 #########################################################
4 /*
5 ~~~~~~ LIST OF FUNCTIONS ~~~~~~
6 getTableList() -- returns an associative array (tableName => tableData, tableData is array(tableCaption, tableDescription, tableIcon)) of tables accessible by current user
7 get_table_groups() -- returns an associative array (table_group => tables_array)
8 logInMember() -- checks POST login. If not valid, redirects to index.php, else returns TRUE
9 getTablePermissions($tn) -- returns an array of permissions allowed for logged member to given table (allowAccess, allowInsert, allowView, allowEdit, allowDelete) -- allowAccess is set to true if any access level is allowed
10 get_sql_fields($tn) -- returns the SELECT part of the table view query
11 get_sql_from($tn[, true]) -- returns the FROM part of the table view query, with full joins, optionally skipping permissions if true passed as 2nd param.
12 get_joined_record($table, $id[, true]) -- returns assoc array of record values for given PK value of given table, with full joins, optionally skipping permissions if true passed as 3rd param.
13 get_defaults($table) -- returns assoc array of table fields as array keys and default values (or empty), excluding automatic values as array values
14 htmlUserBar() -- returns html code for displaying user login status to be used on top of pages.
15 showNotifications($msg, $class) -- returns html code for displaying a notification. If no parameters provided, processes the GET request for possible notifications.
16 parseMySQLDate(a, b) -- returns a if valid mysql date, or b if valid mysql date, or today if b is true, or empty if b is false.
17 parseCode(code) -- calculates and returns special values to be inserted in automatic fields.
18 addFilter(i, filterAnd, filterField, filterOperator, filterValue) -- enforce a filter over data
19 clearFilters() -- clear all filters
20 loadView($view, $data) -- passes $data to templates/{$view}.php and returns the output
21 loadTable($table, $data) -- loads table template, passing $data to it
22 filterDropdownBy($filterable, $filterers, $parentFilterers, $parentPKField, $parentCaption, $parentTable, &$filterableCombo) -- applies cascading drop-downs for a lookup field, returns js code to be inserted into the page
23 br2nl($text) -- replaces all variations of HTML <br> tags with a new line character
24 htmlspecialchars_decode($text) -- inverse of htmlspecialchars()
25 entitiesToUTF8($text) -- convert unicode entities (e.g. Ӓ) to actual UTF8 characters, requires multibyte string PHP extension
26 func_get_args_byref() -- returns an array of arguments passed to a function, by reference
27 permissions_sql($table, $level) -- returns an array containing the FROM and WHERE additions for applying permissions to an SQL query
28 error_message($msg[, $back_url]) -- returns html code for a styled error message .. pass explicit false in second param to suppress back button
29 toMySQLDate($formattedDate, $sep = datalist_date_separator, $ord = datalist_date_format)
30 reIndex(&$arr) -- returns a copy of the given array, with keys replaced by 1-based numeric indices, and values replaced by original keys
31 get_embed($provider, $url[, $width, $height, $retrieve]) -- returns embed code for a given url (supported providers: youtube, googlemap)
32 check_record_permission($table, $id, $perm = 'view') -- returns true if current user has the specified permission $perm ('view', 'edit' or 'delete') for the given recors, false otherwise
33 NavMenus($options) -- returns the HTML code for the top navigation menus. $options is not implemented currently.
34 StyleSheet() -- returns the HTML code for included style sheet files to be placed in the <head> section.
35 getUploadDir($dir) -- if dir is empty, returns upload dir configured in defaultLang.php, else returns $dir.
36 PrepareUploadedFile($FieldName, $MaxSize, $FileTypes='jpg|jpeg|gif|png', $NoRename=false, $dir="") -- validates and moves uploaded file for given $FieldName into the given $dir (or the default one if empty)
37 get_home_links($homeLinks, $default_classes, $tgroup) -- process $homeLinks array and return custom links for homepage. Applies $default_classes to links if links have classes defined, and filters links by $tgroup (using '*' matches all table_group values)
38 quick_search_html($search_term, $label, $separate_dv = true) -- returns HTML code for the quick search box.
39 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40 */
41
42 #########################################################
43
44 function getTableList($skip_authentication = false){
45 $arrAccessTables = array();
46 $arrTables = array(
47 /* 'table_name' => ['table caption', 'homepage description', 'icon', 'table group name'] */
48 'schools' => array('Lớp học', '', 'resources/table_icons/building.png', 'None'),
49 'departments' => array('Môn học', '', 'resources/table_icons/chart_organisation.png', 'None'),
50 'class_time_table' => array('Lịch học', '', 'resources/table_icons/blackboard_drawing.png', 'None'),
51 'exam_time_table' => array('Lịch thi', '', 'resources/table_icons/books.png', 'None'),
52 'personal_time_table' => array('Lịch cá nhân', '', 'resources/table_icons/clock_.png', 'None'),
53 'student_details' => array('Chi tiết sinh viên', '', 'resources/table_icons/administrator.png', 'None'),
54 'notices' => array('Thông báo', '', 'resources/table_icons/clipboard_empty.png', 'None')
55 );
56 if($skip_authentication || getLoggedAdmin()) return $arrTables;
57
58 if(is_array($arrTables)){
59 foreach($arrTables as $tn => $tc){
60 $arrPerm = getTablePermissions($tn);
61 if($arrPerm[0]){
62 $arrAccessTables[$tn] = $tc;
63 }
64 }
65 }
66
67 return $arrAccessTables;
68 }
69
70 #########################################################
71
72 function get_table_groups($skip_authentication = false){
73 $tables = getTableList($skip_authentication);
74 $all_groups = array('None');
75
76 $groups = array();
77 foreach($all_groups as $grp){
78 foreach($tables as $tn => $td){
79 if($td[3] && $td[3] == $grp) $groups[$grp][] = $tn;
80 if(!$td[3]) $groups[0][] = $tn;
81 }
82 }
83
84 return $groups;
85 }
86
87 #########################################################
88
89 function getTablePermissions($tn){
90 static $table_permissions = array();
91 if(isset($table_permissions[$tn])) return $table_permissions[$tn];
92
93 $groupID = getLoggedGroupID();
94 $memberID = makeSafe(getLoggedMemberID());
95 $res_group = sql("select tableName, allowInsert, allowView, allowEdit, allowDelete from membership_grouppermissions where groupID='{$groupID}'", $eo);
96 $res_user = sql("select tableName, allowInsert, allowView, allowEdit, allowDelete from membership_userpermissions where lcase(memberID)='{$memberID}'", $eo);
97
98 while($row = db_fetch_assoc($res_group)){
99 $table_permissions[$row['tableName']] = array(
100 1 => intval($row['allowInsert']),
101 2 => intval($row['allowView']),
102 3 => intval($row['allowEdit']),
103 4 => intval($row['allowDelete']),
104 'insert' => intval($row['allowInsert']),
105 'view' => intval($row['allowView']),
106 'edit' => intval($row['allowEdit']),
107 'delete' => intval($row['allowDelete'])
108 );
109 }
110
111 // user-specific permissions, if specified, overwrite his group permissions
112 while($row = db_fetch_assoc($res_user)){
113 $table_permissions[$row['tableName']] = array(
114 1 => intval($row['allowInsert']),
115 2 => intval($row['allowView']),
116 3 => intval($row['allowEdit']),
117 4 => intval($row['allowDelete']),
118 'insert' => intval($row['allowInsert']),
119 'view' => intval($row['allowView']),
120 'edit' => intval($row['allowEdit']),
121 'delete' => intval($row['allowDelete'])
122 );
123 }
124
125 // if user has any type of access, set 'access' flag
126 foreach($table_permissions as $t => $p){
127 $table_permissions[$t]['access'] = $table_permissions[$t][0] = false;
128
129 if($p['insert'] || $p['view'] || $p['edit'] || $p['delete']){
130 $table_permissions[$t]['access'] = $table_permissions[$t][0] = true;
131 }
132 }
133
134 return $table_permissions[$tn];
135 }
136
137 #########################################################
138
139 function get_sql_fields($table_name){
140 $sql_fields = array(
141 'schools' => "`schools`.`id` as 'id', `schools`.`name` as 'name'",
142 'departments' => "`departments`.`id` as 'id', `departments`.`name` as 'name', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school'",
143 'class_time_table' => "`class_time_table`.`id` as 'id', `class_time_table`.`day` as 'day', TIME_FORMAT(`class_time_table`.`time_start`, '%r') as 'time_start', TIME_FORMAT(`class_time_table`.`time_end`, '%r') as 'time_end', `class_time_table`.`unit_code` as 'unit_code', `class_time_table`.`venue` as 'venue', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school', IF( CHAR_LENGTH(`departments1`.`name`), CONCAT_WS('', `departments1`.`name`), '') as 'department', `class_time_table`.`year_of_study` as 'year_of_study'",
144 'exam_time_table' => "`exam_time_table`.`id` as 'id', if(`exam_time_table`.`date`,date_format(`exam_time_table`.`date`,'%m/%d/%Y'),'') as 'date', TIME_FORMAT(`exam_time_table`.`time_start`, '%r') as 'time_start', TIME_FORMAT(`exam_time_table`.`time_end`, '%r') as 'time_end', `exam_time_table`.`unit_code` as 'unit_code', `exam_time_table`.`venue` as 'venue', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school', IF( CHAR_LENGTH(`departments1`.`name`), CONCAT_WS('', `departments1`.`name`), '') as 'department', `exam_time_table`.`year_of_study` as 'year_of_study'",
145 'personal_time_table' => "`personal_time_table`.`id` as 'id', `personal_time_table`.`day` as 'day', TIME_FORMAT(`personal_time_table`.`time_start`, '%r') as 'time_start', TIME_FORMAT(`personal_time_table`.`time_end`, '%r') as 'time_end', `personal_time_table`.`activity` as 'activity'",
146 'student_details' => "`student_details`.`id` as 'id', `student_details`.`full_name` as 'full_name', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school', IF( CHAR_LENGTH(`departments1`.`name`), CONCAT_WS('', `departments1`.`name`), '') as 'department', `student_details`.`year_of_study` as 'year_of_study', `student_details`.`reg_no` as 'reg_no'",
147 'notices' => "`notices`.`id` as 'id', `notices`.`notice` as 'notice', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school', IF( CHAR_LENGTH(`departments1`.`name`), CONCAT_WS('', `departments1`.`name`), '') as 'department', `notices`.`year_of_study` as 'year_of_study', if(`notices`.`date`,date_format(`notices`.`date`,'%m/%d/%Y'),'') as 'date'"
148 );
149
150 if(isset($sql_fields[$table_name])){
151 return $sql_fields[$table_name];
152 }
153
154 return false;
155 }
156
157 #########################################################
158
159 function get_sql_from($table_name, $skip_permissions = false){
160 $sql_from = array(
161 'schools' => "`schools` ",
162 'departments' => "`departments` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`departments`.`school` ",
163 'class_time_table' => "`class_time_table` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`class_time_table`.`school` LEFT JOIN `departments` as departments1 ON `departments1`.`id`=`class_time_table`.`department` ",
164 'exam_time_table' => "`exam_time_table` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`exam_time_table`.`school` LEFT JOIN `departments` as departments1 ON `departments1`.`id`=`exam_time_table`.`department` ",
165 'personal_time_table' => "`personal_time_table` ",
166 'student_details' => "`student_details` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`student_details`.`school` LEFT JOIN `departments` as departments1 ON `departments1`.`id`=`student_details`.`department` ",
167 'notices' => "`notices` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`notices`.`school` LEFT JOIN `departments` as departments1 ON `departments1`.`id`=`notices`.`department` "
168 );
169
170 $pkey = array(
171 'schools' => 'id',
172 'departments' => 'id',
173 'class_time_table' => 'id',
174 'exam_time_table' => 'id',
175 'personal_time_table' => 'id',
176 'student_details' => 'id',
177 'notices' => 'id'
178 );
179
180 if(isset($sql_from[$table_name])){
181 if($skip_permissions) return $sql_from[$table_name];
182
183 // mm: build the query based on current member's permissions
184 $perm = getTablePermissions($table_name);
185 if($perm[2] == 1){ // view owner only
186 $sql_from[$table_name] .= ", membership_userrecords WHERE `{$table_name}`.`{$pkey[$table_name]}`=membership_userrecords.pkValue and membership_userrecords.tableName='{$table_name}' and lcase(membership_userrecords.memberID)='" . getLoggedMemberID() . "'";
187 }elseif($perm[2] == 2){ // view group only
188 $sql_from[$table_name] .= ", membership_userrecords WHERE `{$table_name}`.`{$pkey[$table_name]}`=membership_userrecords.pkValue and membership_userrecords.tableName='{$table_name}' and membership_userrecords.groupID='" . getLoggedGroupID() . "'";
189 }elseif($perm[2] == 3){ // view all
190 $sql_from[$table_name] .= ' WHERE 1=1';
191 }else{ // view none
192 return false;
193 }
194 return $sql_from[$table_name];
195 }
196
197 return false;
198 }
199
200 #########################################################
201
202 function get_joined_record($table, $id, $skip_permissions = false){
203 $sql_fields = get_sql_fields($table);
204 $sql_from = get_sql_from($table, $skip_permissions);
205
206 if(!$sql_fields || !$sql_from) return false;
207
208 $pk = getPKFieldName($table);
209 if(!$pk) return false;
210
211 $safe_id = makeSafe($id, false);
212 $sql = "SELECT {$sql_fields} FROM {$sql_from} AND `{$table}`.`{$pk}`='{$safe_id}'";
213 $eo['silentErrors'] = true;
214 $res = sql($sql, $eo);
215 if($row = db_fetch_assoc($res)) return $row;
216
217 return false;
218 }
219
220 #########################################################
221
222 function get_defaults($table){
223 /* array of tables and their fields, with default values (or empty), excluding automatic values */
224 $defaults = array(
225 'schools' => array(
226 'id' => '',
227 'name' => ''
228 ),
229 'departments' => array(
230 'id' => '',
231 'name' => '',
232 'school' => ''
233 ),
234 'class_time_table' => array(
235 'id' => '',
236 'day' => '',
237 'time_start' => '',
238 'time_end' => '',
239 'unit_code' => '',
240 'venue' => '',
241 'school' => '',
242 'department' => '',
243 'year_of_study' => ''
244 ),
245 'exam_time_table' => array(
246 'id' => '',
247 'date' => '1',
248 'time_start' => '',
249 'time_end' => '',
250 'unit_code' => '',
251 'venue' => '',
252 'school' => '',
253 'department' => '',
254 'year_of_study' => ''
255 ),
256 'personal_time_table' => array(
257 'id' => '',
258 'day' => '',
259 'time_start' => '',
260 'time_end' => '',
261 'activity' => ''
262 ),
263 'student_details' => array(
264 'id' => '',
265 'full_name' => '',
266 'school' => '',
267 'department' => '',
268 'year_of_study' => '',
269 'reg_no' => ''
270 ),
271 'notices' => array(
272 'id' => '',
273 'notice' => '',
274 'school' => '',
275 'department' => '',
276 'year_of_study' => '',
277 'date' => ''
278 )
279 );
280
281 return isset($defaults[$table]) ? $defaults[$table] : array();
282 }
283
284 #########################################################
285
286 function logInMember(){
287 $redir = 'index.php';
288 if($_POST['signIn'] != ''){
289 if($_POST['username'] != '' && $_POST['password'] != ''){
290 $username = makeSafe(strtolower($_POST['username']));
291 $password = md5($_POST['password']);
292
293 if(sqlValue("select count(1) from membership_users where lcase(memberID)='$username' and passMD5='$password' and isApproved=1 and isBanned=0")==1){
294 $_SESSION['memberID']=$username;
295 $_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
296 if($_POST['rememberMe']==1){
297 @setcookie('Jisort_rememberMe', md5($username.$password), time()+86400*30);
298 }else{
299 @setcookie('Jisort_rememberMe', '', time()-86400*30);
300 }
301
302 // hook: login_ok
303 if(function_exists('login_ok')){
304 $args=array();
305 if(!$redir=login_ok(getMemberInfo(), $args)){
306 $redir='index.php';
307 }
308 }
309
310 redirect($redir);
311 exit;
312 }
313 }
314
315 // hook: login_failed
316 if(function_exists('login_failed')){
317 $args=array();
318 login_failed(array(
319 'username' => $_POST['username'],
320 'password' => $_POST['password'],
321 'IP' => $_SERVER['REMOTE_ADDR']
322 ), $args);
323 }
324
325 if(!headers_sent()) header('HTTP/1.0 403 Forbidden');
326 redirect("index.php?loginFailed=1");
327 exit;
328 }elseif((!$_SESSION['memberID'] || $_SESSION['memberID']==$adminConfig['anonymousMember']) && $_COOKIE['Jisort_rememberMe']!=''){
329 $chk=makeSafe($_COOKIE['Jisort_rememberMe']);
330 if($username=sqlValue("select memberID from membership_users where convert(md5(concat(memberID, passMD5)), char)='$chk' and isBanned=0")){
331 $_SESSION['memberID']=$username;
332 $_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
333 }
334 }
335 }
336
337 #########################################################
338
339 function htmlUserBar(){
340 global $adminConfig, $Translation;
341 if(!defined('PREPEND_PATH')) define('PREPEND_PATH', '');
342
343 ob_start();
344 $home_page = (basename($_SERVER['PHP_SELF'])=='index.php' ? true : false);
345
346 ?>
347 <!-- <nav class="navbar navbar-default navbar-fixed-top hidden-print" role="navigation"> -->
348 <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" role="navigation">
349 <!-- application title is obtained from the name besides the yellow database icon in AppGini, use underscores for spaces -->
350 <a class="navbar-brand" href="<?php echo PREPEND_PATH; ?>index.php"><i class="glyphicon glyphicon-home"></i> Hệ thống xếp lịch học tín chỉ cho sinh viên CNTT</a>
351 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
352 <span class="sr-only">Toggle navigation</span>
353 <span class="icon-bar"></span>
354 <span class="icon-bar"></span>
355 <span class="icon-bar"></span>
356 </button>
357 <div class="collapse navbar-collapse" id="navbarResponsive">
358 <ul class="navbar-nav navbar-sidenav codefly" id="exampleAccordion">
359 <?php if(!$home_page){ ?>
360 <?php echo NavMenus(); ?>
361 <?php } ?>
362 </ul>
363
364 <?php if(getLoggedAdmin()){ ?>
365 <ul class="nav navbar-nav">
366 <a href="<?php echo PREPEND_PATH; ?>admin/pageHome.php" class="btn btn-danger navbar-btn hidden-xs" title="<?php echo html_attr($Translation['admin area']); ?>"><i class="glyphicon glyphicon-cog"></i> <?php echo $Translation['admin area']; ?></a>
367 <a href="<?php echo PREPEND_PATH; ?>admin/pageHome.php" class="btn btn-danger navbar-btn visible-xs btn-lg" title="<?php echo html_attr($Translation['admin area']); ?>"><i class="glyphicon glyphicon-cog"></i> <?php echo $Translation['admin area']; ?></a>
368 </ul>
369 <?php } ?>
370
371 <?php if(!$_GET['signIn'] && !$_GET['loginFailed']){ ?>
372 <?php if(getLoggedMemberID() == $adminConfig['anonymousMember']){ ?>
373 <p class="navbar-text navbar-right"> </p>
374 <a href="<?php echo PREPEND_PATH; ?>index.php?signIn=1" class="btn btn-success navbar-btn navbar-right"><?php echo $Translation['sign in']; ?></a>
375 <p class="navbar-text navbar-right">
376 <?php echo $Translation['not signed in']; ?>
377 </p>
378 <?php }else{ ?>
379 <ul class="nav navbar-nav navbar-right hidden-xs" style="min-width: 330px;">
380 <a class="btn navbar-btn btn-default" href="<?php echo PREPEND_PATH; ?>index.php?signOut=1"><i class="glyphicon glyphicon-log-out"></i> <?php echo $Translation['sign out']; ?></a>
381 <p class="navbar-text">
382 <?php echo $Translation['signed as']; ?> <strong><a href="<?php echo PREPEND_PATH; ?>membership_profile.php" class="navbar-link"><?php echo getLoggedMemberID(); ?></a></strong>
383 </p>
384 </ul>
385 <ul class="nav navbar-nav visible-xs">
386 <a class="btn navbar-btn btn-default btn-lg visible-xs" href="<?php echo PREPEND_PATH; ?>index.php?signOut=1"><i class="glyphicon glyphicon-log-out"></i> <?php echo $Translation['sign out']; ?></a>
387 <p class="navbar-text text-center">
388 <?php echo $Translation['signed as']; ?> <strong><a href="<?php echo PREPEND_PATH; ?>membership_profile.php" class="navbar-link"><?php echo getLoggedMemberID(); ?></a></strong>
389 </p>
390 </ul>
391 <script>
392 /* periodically check if user is still signed in */
393 setInterval(function(){
394 $j.ajax({
395 url: '<?php echo PREPEND_PATH; ?>ajax_check_login.php',
396 success: function(username){
397 if(!username.length) window.location = '<?php echo PREPEND_PATH; ?>index.php?signIn=1';
398 }
399 });
400 }, 60000);
401 </script>
402 <?php } ?>
403 <?php } ?>
404 </div>
405 </nav>
406 <?php
407
408 $html = ob_get_contents();
409 ob_end_clean();
410
411 return $html;
412 }
413
414 #########################################################
415
416 function showNotifications($msg = '', $class = '', $fadeout = true){
417 global $Translation;
418
419 $notify_template_no_fadeout = '<div id="%%ID%%" class="alert alert-dismissable %%CLASS%%" style="display: none; padding-top: 6px; padding-bottom: 6px;">' .
420 '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' .
421 '%%MSG%%</div>' .
422 '<script> jQuery(function(){ /* */ jQuery("#%%ID%%").show("slow"); }); </script>'."\n";
423 $notify_template = '<div id="%%ID%%" class="alert %%CLASS%%" style="display: none; padding-top: 6px; padding-bottom: 6px;">%%MSG%%</div>' .
424 '<script>' .
425 'jQuery(function(){' .
426 'jQuery("#%%ID%%").show("slow", function(){' .
427 'setTimeout(function(){ /* */ jQuery("#%%ID%%").hide("slow"); }, 4000);' .
428 '});' .
429 '});' .
430 '</script>'."\n";
431
432 if(!$msg){ // if no msg, use url to detect message to display
433 if($_REQUEST['record-added-ok'] != ''){
434 $msg = $Translation['new record saved'];
435 $class = 'alert-success';
436 }elseif($_REQUEST['record-added-error'] != ''){
437 $msg = $_SESSION['custom_alert'];
438 unset($_SESSION['custom_alert']);
439 $class = 'alert-danger';
440 $fadeout = false;
441 }elseif($_REQUEST['record-updated-ok'] != ''){
442 $msg = $Translation['record updated'];
443 $class = 'alert-success';
444 }elseif($_REQUEST['record-updated-error'] != ''){
445 $msg = $Translation['Couldn\'t save changes to the record'];
446 $class = 'alert-danger';
447 $fadeout = false;
448 }elseif($_REQUEST['record-deleted-ok'] != ''){
449 $msg = $Translation['The record has been deleted successfully'];
450 $class = 'alert-success';
451 $fadeout = false;
452 }elseif($_REQUEST['record-deleted-error'] != ''){
453 $msg = $Translation['Couldn\'t delete this record'];
454 $class = 'alert-danger';
455 $fadeout = false;
456 }else{
457 return '';
458 }
459 }
460 $id = 'notification-' . rand();
461
462 $out = ($fadeout ? $notify_template : $notify_template_no_fadeout);
463 $out = str_replace('%%ID%%', $id, $out);
464 $out = str_replace('%%MSG%%', $msg, $out);
465 $out = str_replace('%%CLASS%%', $class, $out);
466
467 return $out;
468 }
469
470 #########################################################
471
472 function parseMySQLDate($date, $altDate){
473 // is $date valid?
474 if(preg_match("/^\d{4}-\d{1,2}-\d{1,2}$/", trim($date))){
475 return trim($date);
476 }
477
478 if($date != '--' && preg_match("/^\d{4}-\d{1,2}-\d{1,2}$/", trim($altDate))){
479 return trim($altDate);
480 }
481
482 if($date != '--' && $altDate && intval($altDate)==$altDate){
483 return @date('Y-m-d', @time() + ($altDate >= 1 ? $altDate - 1 : $altDate) * 86400);
484 }
485
486 return '';
487 }
488
489 #########################################################
490
491 function parseCode($code, $isInsert=true, $rawData=false){
492 if($isInsert){
493 $arrCodes=array(
494 '<%%creatorusername%%>' => $_SESSION['memberID'],
495 '<%%creatorgroupid%%>' => $_SESSION['memberGroupID'],
496 '<%%creatorip%%>' => $_SERVER['REMOTE_ADDR'],
497 '<%%creatorgroup%%>' => sqlValue("select name from membership_groups where groupID='{$_SESSION['memberGroupID']}'"),
498
499 '<%%creationdate%%>' => ($rawData ? @date('Y-m-d') : @date('n/j/Y')),
500 '<%%creationtime%%>' => ($rawData ? @date('H:i:s') : @date('h:i:s a')),
501 '<%%creationdatetime%%>' => ($rawData ? @date('Y-m-d H:i:s') : @date('n/j/Y h:i:s a')),
502 '<%%creationtimestamp%%>' => ($rawData ? @date('Y-m-d H:i:s') : @time())
503 );
504 }else{
505 $arrCodes=array(
506 '<%%editorusername%%>' => $_SESSION['memberID'],
507 '<%%editorgroupid%%>' => $_SESSION['memberGroupID'],
508 '<%%editorip%%>' => $_SERVER['REMOTE_ADDR'],
509 '<%%editorgroup%%>' => sqlValue("select name from membership_groups where groupID='{$_SESSION['memberGroupID']}'"),
510
511 '<%%editingdate%%>' => ($rawData ? @date('Y-m-d') : @date('n/j/Y')),
512 '<%%editingtime%%>' => ($rawData ? @date('H:i:s') : @date('h:i:s a')),
513 '<%%editingdatetime%%>' => ($rawData ? @date('Y-m-d H:i:s') : @date('n/j/Y h:i:s a')),
514 '<%%editingtimestamp%%>' => ($rawData ? @date('Y-m-d H:i:s') : @time())
515 );
516 }
517
518 $pc=str_ireplace(array_keys($arrCodes), array_values($arrCodes), $code);
519
520 return $pc;
521 }
522
523 #########################################################
524
525 function addFilter($index, $filterAnd, $filterField, $filterOperator, $filterValue){
526 // validate input
527 if($index < 1 || $index > 80 || !is_int($index)) return false;
528 if($filterAnd != 'or') $filterAnd = 'and';
529 $filterField = intval($filterField);
530
531 /* backward compatibility */
532 if(in_array($filterOperator, $GLOBALS['filter_operators'])){
533 $filterOperator = array_search($filterOperator, $GLOBALS['filter_operators']);
534 }
535
536 if(!in_array($filterOperator, array_keys($GLOBALS['filter_operators']))){
537 $filterOperator = 'like';
538 }
539
540 if(!$filterField){
541 $filterOperator = '';
542 $filterValue = '';
543 }
544
545 $_REQUEST['FilterAnd'][$index] = $filterAnd;
546 $_REQUEST['FilterField'][$index] = $filterField;
547 $_REQUEST['FilterOperator'][$index] = $filterOperator;
548 $_REQUEST['FilterValue'][$index] = $filterValue;
549
550 return true;
551 }
552
553 #########################################################
554
555 function clearFilters(){
556 for($i=1; $i<=80; $i++){
557 addFilter($i, '', 0, '', '');
558 }
559 }
560
561 #########################################################
562
563 if(!function_exists('str_ireplace')){
564 function str_ireplace($search, $replace, $subject){
565 $ret=$subject;
566 if(is_array($search)){
567 for($i=0; $i<count($search); $i++){
568 $ret=str_ireplace($search[$i], $replace[$i], $ret);
569 }
570 }else{
571 $ret=preg_replace('/'.preg_quote($search, '/').'/i', $replace, $ret);
572 }
573
574 return $ret;
575 }
576 }
577
578 #########################################################
579
580 /**
581 * Loads a given view from the templates folder, passing the given data to it
582 * @param $view the name of a php file (without extension) to be loaded from the 'templates' folder
583 * @param $the_data_to_pass_to_the_view (optional) associative array containing the data to pass to the view
584 * @return the output of the parsed view as a string
585 */
586 function loadView($view, $the_data_to_pass_to_the_view=false){
587 global $Translation;
588
589 $view = dirname(__FILE__)."/templates/$view.php";
590 if(!is_file($view)) return false;
591
592 if(is_array($the_data_to_pass_to_the_view)){
593 foreach($the_data_to_pass_to_the_view as $k => $v)
594 $$k = $v;
595 }
596 unset($the_data_to_pass_to_the_view, $k, $v);
597
598 ob_start();
599 @include($view);
600 $out=ob_get_contents();
601 ob_end_clean();
602
603 return $out;
604 }
605
606 #########################################################
607
608 /**
609 * Loads a table template from the templates folder, passing the given data to it
610 * @param $table_name the name of the table whose template is to be loaded from the 'templates' folder
611 * @param $the_data_to_pass_to_the_table associative array containing the data to pass to the table template
612 * @return the output of the parsed table template as a string
613 */
614 function loadTable($table_name, $the_data_to_pass_to_the_table = array()){
615 $dont_load_header = $the_data_to_pass_to_the_table['dont_load_header'];
616 $dont_load_footer = $the_data_to_pass_to_the_table['dont_load_footer'];
617
618 $header = $table = $footer = '';
619
620 if(!$dont_load_header){
621 // try to load tablename-header
622 if(!($header = loadView("{$table_name}-header", $the_data_to_pass_to_the_table))){
623 $header = loadView('table-common-header', $the_data_to_pass_to_the_table);
624 }
625 }
626
627 $table = loadView($table_name, $the_data_to_pass_to_the_table);
628
629 if(!$dont_load_footer){
630 // try to load tablename-footer
631 if(!($footer = loadView("{$table_name}-footer", $the_data_to_pass_to_the_table))){
632 $footer = loadView('table-common-footer', $the_data_to_pass_to_the_table);
633 }
634 }
635
636 return "{$header}{$table}{$footer}";
637 }
638
639 #########################################################
640
641 function filterDropdownBy($filterable, $filterers, $parentFilterers, $parentPKField, $parentCaption, $parentTable, &$filterableCombo){
642 $filterersArray = explode(',', $filterers);
643 $parentFilterersArray = explode(',', $parentFilterers);
644 $parentFiltererList = '`' . implode('`, `', $parentFilterersArray) . '`';
645 $res=sql("SELECT `$parentPKField`, $parentCaption, $parentFiltererList FROM `$parentTable` ORDER BY 2", $eo);
646 $filterableData = array();
647 while($row=db_fetch_row($res)){
648 $filterableData[$row[0]] = $row[1];
649 $filtererIndex = 0;
650 foreach($filterersArray as $filterer){
651 $filterableDataByFilterer[$filterer][$row[$filtererIndex + 2]][$row[0]] = $row[1];
652 $filtererIndex++;
653 }
654 $row[0] = addslashes($row[0]);
655 $row[1] = addslashes($row[1]);
656 $jsonFilterableData .= "\"{$row[0]}\":\"{$row[1]}\",";
657 }
658 $jsonFilterableData .= '}';
659 $jsonFilterableData = '{'.str_replace(',}', '}', $jsonFilterableData);
660 $filterJS = "\nvar {$filterable}_data = $jsonFilterableData;";
661
662 foreach($filterersArray as $filterer){
663 if(is_array($filterableDataByFilterer[$filterer])) foreach($filterableDataByFilterer[$filterer] as $filtererItem => $filterableItem){
664 $jsonFilterableDataByFilterer[$filterer] .= '"'.addslashes($filtererItem).'":{';
665 foreach($filterableItem as $filterableItemID => $filterableItemData){
666 $jsonFilterableDataByFilterer[$filterer] .= '"'.addslashes($filterableItemID).'":"'.addslashes($filterableItemData).'",';
667 }
668 $jsonFilterableDataByFilterer[$filterer] .= '},';
669 }
670 $jsonFilterableDataByFilterer[$filterer] .= '}';
671 $jsonFilterableDataByFilterer[$filterer] = '{'.str_replace(',}', '}', $jsonFilterableDataByFilterer[$filterer]);
672
673 $filterJS.="\n\n// code for filtering {$filterable} by {$filterer}\n";
674 $filterJS.="\nvar {$filterable}_data_by_{$filterer} = {$jsonFilterableDataByFilterer[$filterer]}; ";
675 $filterJS.="\nvar selected_{$filterable} = \$j('#{$filterable}').val();";
676 $filterJS.="\nvar {$filterable}_change_by_{$filterer} = function(){";
677 $filterJS.="\n\t$('{$filterable}').options.length=0;";
678 $filterJS.="\n\t$('{$filterable}').options[0] = new Option();";
679 $filterJS.="\n\tif(\$j('#{$filterer}').val()){";
680 $filterJS.="\n\t\tfor({$filterable}_item in {$filterable}_data_by_{$filterer}[\$j('#{$filterer}').val()]){";
681 $filterJS.="\n\t\t\t$('{$filterable}').options[$('{$filterable}').options.length] = new Option(";
682 $filterJS.="\n\t\t\t\t{$filterable}_data_by_{$filterer}[\$j('#{$filterer}').val()][{$filterable}_item],";
683 $filterJS.="\n\t\t\t\t{$filterable}_item,";
684 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false),";
685 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false)";
686 $filterJS.="\n\t\t\t);";
687 $filterJS.="\n\t\t}";
688 $filterJS.="\n\t}else{";
689 $filterJS.="\n\t\tfor({$filterable}_item in {$filterable}_data){";
690 $filterJS.="\n\t\t\t$('{$filterable}').options[$('{$filterable}').options.length] = new Option(";
691 $filterJS.="\n\t\t\t\t{$filterable}_data[{$filterable}_item],";
692 $filterJS.="\n\t\t\t\t{$filterable}_item,";
693 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false),";
694 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false)";
695 $filterJS.="\n\t\t\t);";
696 $filterJS.="\n\t\t}";
697 $filterJS.="\n\t\tif(selected_{$filterable} && selected_{$filterable} == \$j('#{$filterable}').val()){";
698 $filterJS.="\n\t\t\tfor({$filterer}_item in {$filterable}_data_by_{$filterer}){";
699 $filterJS.="\n\t\t\t\tfor({$filterable}_item in {$filterable}_data_by_{$filterer}[{$filterer}_item]){";
700 $filterJS.="\n\t\t\t\t\tif({$filterable}_item == selected_{$filterable}){";
701 $filterJS.="\n\t\t\t\t\t\t$('{$filterer}').value = {$filterer}_item;";
702 $filterJS.="\n\t\t\t\t\t\tbreak;";
703 $filterJS.="\n\t\t\t\t\t}";
704 $filterJS.="\n\t\t\t\t}";
705 $filterJS.="\n\t\t\t\tif({$filterable}_item == selected_{$filterable}) break;";
706 $filterJS.="\n\t\t\t}";
707 $filterJS.="\n\t\t}";
708 $filterJS.="\n\t}";
709 $filterJS.="\n\t$('{$filterable}').highlight();";
710 $filterJS.="\n};";
711 $filterJS.="\n$('{$filterer}').observe('change', function(){ /* */ window.setTimeout({$filterable}_change_by_{$filterer}, 25); });";
712 $filterJS.="\n";
713 }
714
715 $filterableCombo = new Combo;
716 $filterableCombo->ListType = 0;
717 $filterableCombo->ListItem = array_slice(array_values($filterableData), 0, 10);
718 $filterableCombo->ListData = array_slice(array_keys($filterableData), 0, 10);
719 $filterableCombo->SelectName = $filterable;
720 $filterableCombo->AllowNull = true;
721
722 return $filterJS;
723 }
724
725 #########################################################
726 function br2nl($text){
727 return preg_replace('/\<br(\s*)?\/?\>/i', "\n", $text);
728 }
729
730 #########################################################
731
732 if(!function_exists('htmlspecialchars_decode')){
733 function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT){
734 return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
735 }
736 }
737
738 #########################################################
739
740 function entitiesToUTF8($input){
741 return preg_replace_callback('/(&#[0-9]+;)/', '_toUTF8', $input);
742 }
743
744 function _toUTF8($m){
745 if(function_exists('mb_convert_encoding')){
746 return mb_convert_encoding($m[1], "UTF-8", "HTML-ENTITIES");
747 }else{
748 return $m[1];
749 }
750 }
751
752 #########################################################
753
754 function func_get_args_byref() {
755 if(!function_exists('debug_backtrace')) return false;
756
757 $trace = debug_backtrace();
758 return $trace[1]['args'];
759 }
760
761 #########################################################
762
763 function permissions_sql($table, $level = 'all'){
764 if(!in_array($level, array('user', 'group'))){ $level = 'all'; }
765 $perm = getTablePermissions($table);
766 $from = '';
767 $where = '';
768 $pk = getPKFieldName($table);
769
770 if($perm[2] == 1 || ($perm[2] > 1 && $level == 'user')){ // view owner only
771 $from = 'membership_userrecords';
772 $where = "(`$table`.`$pk`=membership_userrecords.pkValue and membership_userrecords.tableName='$table' and lcase(membership_userrecords.memberID)='".getLoggedMemberID()."')";
773 }elseif($perm[2] == 2 || ($perm[2] > 2 && $level == 'group')){ // view group only
774 $from = 'membership_userrecords';
775 $where = "(`$table`.`$pk`=membership_userrecords.pkValue and membership_userrecords.tableName='$table' and membership_userrecords.groupID='".getLoggedGroupID()."')";
776 }elseif($perm[2] == 3){ // view all
777 // no further action
778 }elseif($perm[2] == 0){ // view none
779 return false;
780 }
781
782 return array('where' => $where, 'from' => $from, 0 => $where, 1 => $from);
783 }
784
785 #########################################################
786
787 function error_message($msg, $back_url = '', $full_page = true){
788 $curr_dir = dirname(__FILE__);
789 global $Translation;
790
791 ob_start();
792
793 if($full_page) include_once($curr_dir . '/header.php');
794
795 echo '<div class="panel panel-danger">';
796 echo '<div class="panel-heading"><h3 class="panel-title">' . $Translation['error:'] . '</h3></div>';
797 echo '<div class="panel-body"><p class="text-danger">' . $msg . '</p>';
798 if($back_url !== false){ // explicitly passing false suppresses the back link completely
799 echo '<div class="text-center">';
800 if($back_url){
801 echo '<a href="' . $back_url . '" class="btn btn-danger btn-lg vspacer-lg"><i class="glyphicon glyphicon-chevron-left"></i> ' . $Translation['< back'] . '</a>';
802 }else{
803 echo '<a href="#" class="btn btn-danger btn-lg vspacer-lg" onclick="history.go(-1); return false;"><i class="glyphicon glyphicon-chevron-left"></i> ' . $Translation['< back'] . '</a>';
804 }
805 echo '</div>';
806 }
807 echo '</div>';
808 echo '</div>';
809
810 if($full_page) include_once($curr_dir . '/footer.php');
811
812 $out = ob_get_contents();
813 ob_end_clean();
814
815 return $out;
816 }
817
818 #########################################################
819
820 function toMySQLDate($formattedDate, $sep = datalist_date_separator, $ord = datalist_date_format){
821 // extract date elements
822 $de=explode($sep, $formattedDate);
823 $mySQLDate=intval($de[strpos($ord, 'Y')]).'-'.intval($de[strpos($ord, 'm')]).'-'.intval($de[strpos($ord, 'd')]);
824 return $mySQLDate;
825 }
826
827 #########################################################
828
829 function reIndex(&$arr){
830 $i=1;
831 foreach($arr as $n=>$v){
832 $arr2[$i]=$n;
833 $i++;
834 }
835 return $arr2;
836 }
837
838 #########################################################
839
840 function get_embed($provider, $url, $max_width = '', $max_height = '', $retrieve = 'html'){
841 global $Translation;
842 if(!$url) return '';
843
844 $providers = array(
845 'youtube' => array('oembed' => 'http://www.youtube.com/oembed?'),
846 'googlemap' => array('oembed' => '', 'regex' => '/^http.*\.google\..*maps/i')
847 );
848
849 if(!isset($providers[$provider])){
850 return '<div class="text-danger">' . $Translation['invalid provider'] . '</div>';
851 }
852
853 if(isset($providers[$provider]['regex']) && !preg_match($providers[$provider]['regex'], $url)){
854 return '<div class="text-danger">' . $Translation['invalid url'] . '</div>';
855 }
856
857 if($providers[$provider]['oembed']){
858 $oembed = $providers[$provider]['oembed'] . 'url=' . urlencode($url) . "&maxwidth={$max_width}&maxheight={$max_height}&format=json";
859 $data_json = request_cache($oembed);
860
861 $data = json_decode($data_json, true);
862 if($data === null){
863 /* an error was returned rather than a json string */
864 if($retrieve == 'html') return "<div class=\"text-danger\">{$data_json}\n<!-- {$oembed} --></div>";
865 return '';
866 }
867
868 return (isset($data[$retrieve]) ? $data[$retrieve] : $data['html']);
869 }
870
871 /* special cases (where there is no oEmbed provider) */
872 if($provider == 'googlemap') return get_embed_googlemap($url, $max_width, $max_height, $retrieve);
873
874 return '<div class="text-danger">Invalid provider!</div>';
875 }
876
877 #########################################################
878
879 function get_embed_googlemap($url, $max_width = '', $max_height = '', $retrieve = 'html'){
880 global $Translation;
881 $url_parts = parse_url($url);
882 $coords_regex = '/-?\d+(\.\d+)?[,+]-?\d+(\.\d+)?(,\d{1,2}z)?/'; /* https://stackoverflow.com/questions/2660201 */
883
884 if(preg_match($coords_regex, $url_parts['path'] . '?' . $url_parts['query'], $m)){
885 list($lat, $long, $zoom) = explode(',', $m[0]);
886 $zoom = intval($zoom);
887 if(!$zoom) $zoom = 10; /* default zoom */
888 if(!$max_height) $max_height = 360;
889 if(!$max_width) $max_width = 480;
890
891 $api_key = '';
892 $embed_url = "https://www.google.com/maps/embed/v1/view?key={$api_key}¢er={$lat},{$long}&zoom={$zoom}&maptype=roadmap";
893 $thumbnail_url = "https://maps.googleapis.com/maps/api/staticmap?key={$api_key}¢er={$lat},{$long}&zoom={$zoom}&maptype=roadmap&size={$max_width}x{$max_height}";
894
895 if($retrieve == 'html'){
896 return "<iframe width=\"{$max_width}\" height=\"{$max_height}\" frameborder=\"0\" style=\"border:0\" src=\"{$embed_url}\"></iframe>";
897 }else{
898 return $thumbnail_url;
899 }
900 }else{
901 return '<div class="text-danger">' . $Translation['cant retrieve coordinates from url'] . '</div>';
902 }
903 }
904
905 #########################################################
906
907 function request_cache($request, $force_fetch = false){
908 $max_cache_lifetime = 7 * 86400; /* max cache lifetime in seconds before refreshing from source */
909
910 /* membership_cache table exists? if not, create it */
911 static $cache_table_exists = false;
912 if(!$cache_table_exists && !$force_fetch){
913 $te = sqlValue("show tables like 'membership_cache'");
914 if(!$te){
915 if(!sql("CREATE TABLE `membership_cache` (`request` VARCHAR(100) NOT NULL, `request_ts` INT, `response` TEXT NOT NULL, PRIMARY KEY (`request`))", $eo)){
916 /* table can't be created, so force fetching request */
917 return request_cache($request, true);
918 }
919 }
920 $cache_table_exists = true;
921 }
922
923 /* retrieve response from cache if exists */
924 if(!$force_fetch){
925 $res = sql("select response, request_ts from membership_cache where request='" . md5($request) . "'", $eo);
926 if(!$row = db_fetch_array($res)) return request_cache($request, true);
927
928 $response = $row[0];
929 $response_ts = $row[1];
930 if($response_ts < time() - $max_cache_lifetime) return request_cache($request, true);
931 }
932
933 /* if no response in cache, issue a request */
934 if(!$response || $force_fetch){
935 $response = @file_get_contents($request);
936 if($response === false){
937 $error = error_get_last();
938 $error_message = preg_replace('/.*: (.*)/', '$1', $error['message']);
939 return $error_message;
940 }elseif($cache_table_exists){
941 /* store response in cache */
942 $ts = time();
943 sql("replace into membership_cache set request='" . md5($request) . "', request_ts='{$ts}', response='" . makeSafe($response, false) . "'", $eo);
944 }
945 }
946
947 return $response;
948 }
949
950 #########################################################
951
952 function check_record_permission($table, $id, $perm = 'view'){
953 if($perm != 'edit' && $perm != 'delete') $perm = 'view';
954
955 $perms = getTablePermissions($table);
956 if(!$perms[$perm]) return false;
957
958 $safe_id = makeSafe($id);
959 $safe_table = makeSafe($table);
960
961 if($perms[$perm] == 1){ // own records only
962 $username = getLoggedMemberID();
963 $owner = sqlValue("select memberID from membership_userrecords where tableName='{$safe_table}' and pkValue='{$safe_id}'");
964 if($owner == $username) return true;
965 }elseif($perms[$perm] == 2){ // group records
966 $group_id = getLoggedGroupID();
967 $owner_group_id = sqlValue("select groupID from membership_userrecords where tableName='{$safe_table}' and pkValue='{$safe_id}'");
968 if($owner_group_id == $group_id) return true;
969 }elseif($perms[$perm] == 3){ // all records
970 return true;
971 }
972
973 return false;
974 }
975
976 #########################################################
977
978 function NavMenus($options = array()){
979 if(!defined('PREPEND_PATH')) define('PREPEND_PATH', '');
980 global $Translation;
981 $prepend_path = PREPEND_PATH;
982
983 /* default options */
984 if(empty($options)){
985 $options = array(
986 'tabs' => 7
987 );
988 }
989
990 $table_group_name = array_keys(get_table_groups()); /* 0 => group1, 1 => group2 .. */
991 /* if only one group named 'None', set to translation of 'select a table' */
992 if((count($table_group_name) == 1 && $table_group_name[0] == 'None') || count($table_group_name) < 1) $table_group_name[0] = $Translation['select a table'];
993 $table_group_index = array_flip($table_group_name); /* group1 => 0, group2 => 1 .. */
994 $menu = array_fill(0, count($table_group_name), '');
995
996 $t = time();
997 $arrTables = getTableList();
998 if(is_array($arrTables)){
999 foreach($arrTables as $tn => $tc){
1000 /* ---- list of tables where hide link in nav menu is set ---- */
1001 $tChkHL = array_search($tn, array());
1002
1003 /* ---- list of tables where filter first is set ---- */
1004 $tChkFF = array_search($tn, array());
1005 if($tChkFF !== false && $tChkFF !== null){
1006 $searchFirst = '&Filter_x=1';
1007 }else{
1008 $searchFirst = '';
1009 }
1010
1011 /* when no groups defined, $table_group_index['None'] is NULL, so $menu_index is still set to 0 */
1012 $menu_index = intval($table_group_index[$tc[3]]);
1013 if(!$tChkHL && $tChkHL !== 0) $menu[$menu_index] .= "<li class=\"nav-item\"><a href=\"{$prepend_path}{$tn}_view.php?t={$t}{$searchFirst}\"><img src=\"{$prepend_path}" . ($tc[2] ? $tc[2] : 'blank.gif') . "\" height=\"32\"> {$tc[0]}</a></li>";
1014 }
1015 }
1016
1017 // custom nav links, as defined in "hooks/links-navmenu.php"
1018 global $navLinks;
1019 if(is_array($navLinks)){
1020 $memberInfo = getMemberInfo();
1021 $links_added = array();
1022 foreach($navLinks as $link){
1023 if(!isset($link['url']) || !isset($link['title'])) continue;
1024 if($memberInfo['admin'] || @in_array($memberInfo['group'], $link['groups']) || @in_array('*', $link['groups'])){
1025 $menu_index = intval($link['table_group']);
1026 if(!$links_added[$menu_index]) $menu[$menu_index] .= '<li class="divider"></li>';
1027
1028 /* add prepend_path to custom links if they aren't absolute links */
1029 if(!preg_match('/^(http|\/\/)/i', $link['url'])) $link['url'] = $prepend_path . $link['url'];
1030 if(!preg_match('/^(http|\/\/)/i', $link['icon']) && $link['icon']) $link['icon'] = $prepend_path . $link['icon'];
1031
1032 $menu[$menu_index] .= "<li class=\"nav-item\"><a href=\"{$link['url']}\"><img src=\"" . ($link['icon'] ? $link['icon'] : "{$prepend_path}blank.gif") . "\" height=\"32\"> {$link['title']}</a></li>";
1033 $links_added[$menu_index]++;
1034 }
1035 }
1036 }
1037
1038 $menu_wrapper = '';
1039 for($i = 0; $i < count($menu); $i++){
1040 $menu_wrapper .= <<<EOT
1041 {$menu[$i]}
1042 <!--<li class="dropdown">-->
1043 <a href="#" class="dropdown-toggle" data-toggle="dropdown">{$table_group_name[$i]} <b class="caret"></b></a>
1044 <!-- <ul class="dropdown-menu" role="menu">{$menu[$i]}</ul> -->
1045 <!--</li>-->
1046 EOT;
1047 }
1048
1049 return $menu_wrapper;
1050 }
1051
1052 #########################################################
1053
1054 function StyleSheet(){
1055 if(!defined('PREPEND_PATH')) define('PREPEND_PATH', '');
1056 $prepend_path = PREPEND_PATH;
1057
1058 $css_links = <<<EOT
1059
1060 <link rel="stylesheet" href="{$prepend_path}resources/initializr/css/bootstrap.css">
1061 <link rel="stylesheet" href="{$prepend_path}resources/lightbox/css/lightbox.css" media="screen">
1062 <link rel="stylesheet" href="{$prepend_path}resources/select2/select2.css" media="screen">
1063 <link rel="stylesheet" href="{$prepend_path}resources/timepicker/bootstrap-timepicker.min.css" media="screen">
1064 <link rel="stylesheet" href="{$prepend_path}dynamic.css.php">
1065 EOT;
1066
1067 return $css_links;
1068 }
1069
1070 #########################################################
1071
1072 function getUploadDir($dir){
1073 global $Translation;
1074
1075 if($dir==""){
1076 $dir=$Translation['ImageFolder'];
1077 }
1078
1079 if(substr($dir, -1)!="/"){
1080 $dir.="/";
1081 }
1082
1083 return $dir;
1084 }
1085
1086 #########################################################
1087
1088 function PrepareUploadedFile($FieldName, $MaxSize, $FileTypes = 'jpg|jpeg|gif|png', $NoRename = false, $dir = ''){
1089 global $Translation;
1090 $f = $_FILES[$FieldName];
1091 if($f['error'] == 4 || !$f['name']) return '';
1092
1093 $dir = getUploadDir($dir);
1094
1095 /* get php.ini upload_max_filesize in bytes */
1096 $php_upload_size_limit = trim(ini_get('upload_max_filesize'));
1097 $last = strtolower($php_upload_size_limit[strlen($php_upload_size_limit) - 1]);
1098 switch($last){
1099 case 'g':
1100 $php_upload_size_limit *= 1024;
1101 case 'm':
1102 $php_upload_size_limit *= 1024;
1103 case 'k':
1104 $php_upload_size_limit *= 1024;
1105 }
1106
1107 $MaxSize = min($MaxSize, $php_upload_size_limit);
1108
1109 if($f['size'] > $MaxSize || $f['error']){
1110 echo error_message(str_replace('<MaxSize>', intval($MaxSize / 1024), $Translation['file too large']));
1111 exit;
1112 }
1113 if(!preg_match('/\.(' . $FileTypes . ')$/i', $f['name'], $ft)){
1114 echo error_message(str_replace('<FileTypes>', str_replace('|', ', ', $FileTypes), $Translation['invalid file type']));
1115 exit;
1116 }
1117
1118 $name = str_replace(' ', '_', $f['name']);
1119 if(!$NoRename) $name = substr(md5(microtime() . rand(0, 100000)), -17) . $ft[0];
1120
1121 if(!file_exists($dir)) @mkdir($dir, 0777);
1122
1123 if(!@move_uploaded_file($f['tmp_name'], $dir . $name)){
1124 echo error_message("Couldn't save the uploaded file. Try chmoding the upload folder '{$dir}' to 777.");
1125 exit;
1126 }
1127
1128 @chmod($dir . $name, 0666);
1129 return $name;
1130 }
1131
1132 #########################################################
1133
1134 function get_home_links($homeLinks, $default_classes, $tgroup = ''){
1135 if(!is_array($homeLinks) || !count($homeLinks)) return '';
1136
1137 $memberInfo = getMemberInfo();
1138
1139 ob_start();
1140 foreach($homeLinks as $link){
1141 if(!isset($link['url']) || !isset($link['title'])) continue;
1142 if($tgroup != $link['table_group'] && $tgroup != '*') continue;
1143
1144 /* fall-back classes if none defined */
1145 if(!$link['grid_column_classes']) $link['grid_column_classes'] = $default_classes['grid_column'];
1146 if(!$link['panel_classes']) $link['panel_classes'] = $default_classes['panel'];
1147 if(!$link['link_classes']) $link['link_classes'] = $default_classes['link'];
1148
1149 if($memberInfo['admin'] || @in_array($memberInfo['group'], $link['groups']) || @in_array('*', $link['groups'])){
1150 ?>
1151 <div class="col-xs-12 <?php echo $link['grid_column_classes']; ?>">
1152 <div class="panel <?php echo $link['panel_classes']; ?>">
1153 <div class="panel-body">
1154 <a class="btn btn-block btn-lg <?php echo $link['link_classes']; ?>" title="<?php echo preg_replace("/&(#[0-9]+|[a-z]+);/i", "&$1;", html_attr(strip_tags($link['description']))); ?>" href="<?php echo $link['url']; ?>"><?php echo ($link['icon'] ? '<img src="' . $link['icon'] . '">' : ''); ?><strong><?php echo $link['title']; ?></strong></a>
1155 <div class="panel-body-description"><?php echo $link['description']; ?></div>
1156 </div>
1157 </div>
1158 </div>
1159 <?php
1160 }
1161 }
1162
1163 $html = ob_get_contents();
1164 ob_end_clean();
1165
1166 return $html;
1167 }
1168
1169 #########################################################
1170
1171 function quick_search_html($search_term, $label, $separate_dv = true){
1172 global $Translation;
1173
1174 $safe_search = html_attr($search_term);
1175 $safe_label = html_attr($label);
1176 $safe_clear_label = html_attr($Translation['Reset Filters']);
1177
1178 if($separate_dv){
1179 $reset_selection = "document.myform.SelectedID.value = '';";
1180 }else{
1181 $reset_selection = "document.myform.writeAttribute('novalidate', 'novalidate');";
1182 }
1183 $reset_selection .= ' document.myform.NoDV.value=1; return true;';
1184
1185 $html = <<<EOT
1186 <div class="input-group" id="quick-search">
1187 <input type="text" id="SearchString" name="SearchString" value="{$safe_search}" class="form-control" placeholder="{$safe_label}">
1188 <span class="input-group-btn">
1189 <button name="Search_x" value="1" id="Search" type="submit" onClick="{$reset_selection}" class="btn btn-default" title="{$safe_label}"><i class="glyphicon glyphicon-search"></i></button>
1190 <button name="ClearQuickSearch" value="1" id="ClearQuickSearch" type="submit" onClick="\$j('#SearchString').val(''); {$reset_selection}" class="btn btn-default" title="{$safe_clear_label}"><i class="glyphicon glyphicon-remove-circle"></i></button>
1191 </span>
1192 </div>
1193 EOT;
1194 return $html;
1195 }
1196
1197 #########################################################
2
3 #########################################################
4 /*
5 ~~~~~~ LIST OF FUNCTIONS ~~~~~~
6 getTableList() -- returns an associative array (tableName => tableData, tableData is array(tableCaption, tableDescription, tableIcon)) of tables accessible by current user
7 get_table_groups() -- returns an associative array (table_group => tables_array)
8 logInMember() -- checks POST login. If not valid, redirects to index.php, else returns TRUE
9 getTablePermissions($tn) -- returns an array of permissions allowed for logged member to given table (allowAccess, allowInsert, allowView, allowEdit, allowDelete) -- allowAccess is set to true if any access level is allowed
10 get_sql_fields($tn) -- returns the SELECT part of the table view query
11 get_sql_from($tn[, true]) -- returns the FROM part of the table view query, with full joins, optionally skipping permissions if true passed as 2nd param.
12 get_joined_record($table, $id[, true]) -- returns assoc array of record values for given PK value of given table, with full joins, optionally skipping permissions if true passed as 3rd param.
13 get_defaults($table) -- returns assoc array of table fields as array keys and default values (or empty), excluding automatic values as array values
14 htmlUserBar() -- returns html code for displaying user login status to be used on top of pages.
15 showNotifications($msg, $class) -- returns html code for displaying a notification. If no parameters provided, processes the GET request for possible notifications.
16 parseMySQLDate(a, b) -- returns a if valid mysql date, or b if valid mysql date, or today if b is true, or empty if b is false.
17 parseCode(code) -- calculates and returns special values to be inserted in automatic fields.
18 addFilter(i, filterAnd, filterField, filterOperator, filterValue) -- enforce a filter over data
19 clearFilters() -- clear all filters
20 loadView($view, $data) -- passes $data to templates/{$view}.php and returns the output
21 loadTable($table, $data) -- loads table template, passing $data to it
22 filterDropdownBy($filterable, $filterers, $parentFilterers, $parentPKField, $parentCaption, $parentTable, &$filterableCombo) -- applies cascading drop-downs for a lookup field, returns js code to be inserted into the page
23 br2nl($text) -- replaces all variations of HTML <br> tags with a new line character
24 htmlspecialchars_decode($text) -- inverse of htmlspecialchars()
25 entitiesToUTF8($text) -- convert unicode entities (e.g. Ӓ) to actual UTF8 characters, requires multibyte string PHP extension
26 func_get_args_byref() -- returns an array of arguments passed to a function, by reference
27 permissions_sql($table, $level) -- returns an array containing the FROM and WHERE additions for applying permissions to an SQL query
28 error_message($msg[, $back_url]) -- returns html code for a styled error message .. pass explicit false in second param to suppress back button
29 toMySQLDate($formattedDate, $sep = datalist_date_separator, $ord = datalist_date_format)
30 reIndex(&$arr) -- returns a copy of the given array, with keys replaced by 1-based numeric indices, and values replaced by original keys
31 get_embed($provider, $url[, $width, $height, $retrieve]) -- returns embed code for a given url (supported providers: youtube, googlemap)
32 check_record_permission($table, $id, $perm = 'view') -- returns true if current user has the specified permission $perm ('view', 'edit' or 'delete') for the given recors, false otherwise
33 NavMenus($options) -- returns the HTML code for the top navigation menus. $options is not implemented currently.
34 StyleSheet() -- returns the HTML code for included style sheet files to be placed in the <head> section.
35 getUploadDir($dir) -- if dir is empty, returns upload dir configured in defaultLang.php, else returns $dir.
36 PrepareUploadedFile($FieldName, $MaxSize, $FileTypes='jpg|jpeg|gif|png', $NoRename=false, $dir="") -- validates and moves uploaded file for given $FieldName into the given $dir (or the default one if empty)
37 get_home_links($homeLinks, $default_classes, $tgroup) -- process $homeLinks array and return custom links for homepage. Applies $default_classes to links if links have classes defined, and filters links by $tgroup (using '*' matches all table_group values)
38 quick_search_html($search_term, $label, $separate_dv = true) -- returns HTML code for the quick search box.
39 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
40 */
41
42 #########################################################
43
44 function getTableList($skip_authentication = false){
45 $arrAccessTables = array();
46 $arrTables = array(
47 /* 'table_name' => ['table caption', 'homepage description', 'icon', 'table group name'] */
48 'schools' => array('Lớp học', '', 'resources/table_icons/building.png', 'None'),
49 'departments' => array('Môn học', '', 'resources/table_icons/chart_organisation.png', 'None'),
50 'class_time_table' => array('Lịch học', '', 'resources/table_icons/blackboard_drawing.png', 'None'),
51 'exam_time_table' => array('Lịch thi', '', 'resources/table_icons/books.png', 'None'),
52 'personal_time_table' => array('Lịch cá nhân', '', 'resources/table_icons/clock_.png', 'None'),
53 'student_details' => array('Chi tiết sinh viên', '', 'resources/table_icons/administrator.png', 'None'),
54 'notices' => array('Thông báo', '', 'resources/table_icons/clipboard_empty.png', 'None')
55 );
56 if($skip_authentication || getLoggedAdmin()) return $arrTables;
57
58 if(is_array($arrTables)){
59 foreach($arrTables as $tn => $tc){
60 $arrPerm = getTablePermissions($tn);
61 if($arrPerm[0]){
62 $arrAccessTables[$tn] = $tc;
63 }
64 }
65 }
66
67 return $arrAccessTables;
68 }
69
70 #########################################################
71
72 function get_table_groups($skip_authentication = false){
73 $tables = getTableList($skip_authentication);
74 $all_groups = array('None');
75
76 $groups = array();
77 foreach($all_groups as $grp){
78 foreach($tables as $tn => $td){
79 if($td[3] && $td[3] == $grp) $groups[$grp][] = $tn;
80 if(!$td[3]) $groups[0][] = $tn;
81 }
82 }
83
84 return $groups;
85 }
86
87 #########################################################
88
89 function getTablePermissions($tn){
90 static $table_permissions = array();
91 if(isset($table_permissions[$tn])) return $table_permissions[$tn];
92
93 $groupID = getLoggedGroupID();
94 $memberID = makeSafe(getLoggedMemberID());
95 $res_group = sql("select tableName, allowInsert, allowView, allowEdit, allowDelete from membership_grouppermissions where groupID='{$groupID}'", $eo);
96 $res_user = sql("select tableName, allowInsert, allowView, allowEdit, allowDelete from membership_userpermissions where lcase(memberID)='{$memberID}'", $eo);
97
98 while($row = db_fetch_assoc($res_group)){
99 $table_permissions[$row['tableName']] = array(
100 1 => intval($row['allowInsert']),
101 2 => intval($row['allowView']),
102 3 => intval($row['allowEdit']),
103 4 => intval($row['allowDelete']),
104 'insert' => intval($row['allowInsert']),
105 'view' => intval($row['allowView']),
106 'edit' => intval($row['allowEdit']),
107 'delete' => intval($row['allowDelete'])
108 );
109 }
110
111 // user-specific permissions, if specified, overwrite his group permissions
112 while($row = db_fetch_assoc($res_user)){
113 $table_permissions[$row['tableName']] = array(
114 1 => intval($row['allowInsert']),
115 2 => intval($row['allowView']),
116 3 => intval($row['allowEdit']),
117 4 => intval($row['allowDelete']),
118 'insert' => intval($row['allowInsert']),
119 'view' => intval($row['allowView']),
120 'edit' => intval($row['allowEdit']),
121 'delete' => intval($row['allowDelete'])
122 );
123 }
124
125 // if user has any type of access, set 'access' flag
126 foreach($table_permissions as $t => $p){
127 $table_permissions[$t]['access'] = $table_permissions[$t][0] = false;
128
129 if($p['insert'] || $p['view'] || $p['edit'] || $p['delete']){
130 $table_permissions[$t]['access'] = $table_permissions[$t][0] = true;
131 }
132 }
133
134 return $table_permissions[$tn];
135 }
136
137 #########################################################
138
139 function get_sql_fields($table_name){
140 $sql_fields = array(
141 'schools' => "`schools`.`id` as 'id', `schools`.`name` as 'name'",
142 'departments' => "`departments`.`id` as 'id', `departments`.`name` as 'name', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school'",
143 'class_time_table' => "`class_time_table`.`id` as 'id', `class_time_table`.`day` as 'day', TIME_FORMAT(`class_time_table`.`time_start`, '%r') as 'time_start', TIME_FORMAT(`class_time_table`.`time_end`, '%r') as 'time_end', `class_time_table`.`unit_code` as 'unit_code', `class_time_table`.`venue` as 'venue', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school', IF( CHAR_LENGTH(`departments1`.`name`), CONCAT_WS('', `departments1`.`name`), '') as 'department', `class_time_table`.`year_of_study` as 'year_of_study'",
144 'exam_time_table' => "`exam_time_table`.`id` as 'id', if(`exam_time_table`.`date`,date_format(`exam_time_table`.`date`,'%m/%d/%Y'),'') as 'date', TIME_FORMAT(`exam_time_table`.`time_start`, '%r') as 'time_start', TIME_FORMAT(`exam_time_table`.`time_end`, '%r') as 'time_end', `exam_time_table`.`unit_code` as 'unit_code', `exam_time_table`.`venue` as 'venue', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school', IF( CHAR_LENGTH(`departments1`.`name`), CONCAT_WS('', `departments1`.`name`), '') as 'department', `exam_time_table`.`year_of_study` as 'year_of_study'",
145 'personal_time_table' => "`personal_time_table`.`id` as 'id', `personal_time_table`.`day` as 'day', TIME_FORMAT(`personal_time_table`.`time_start`, '%r') as 'time_start', TIME_FORMAT(`personal_time_table`.`time_end`, '%r') as 'time_end', `personal_time_table`.`activity` as 'activity'",
146 'student_details' => "`student_details`.`id` as 'id', `student_details`.`full_name` as 'full_name', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school', IF( CHAR_LENGTH(`departments1`.`name`), CONCAT_WS('', `departments1`.`name`), '') as 'department', `student_details`.`year_of_study` as 'year_of_study', `student_details`.`reg_no` as 'reg_no'",
147 'notices' => "`notices`.`id` as 'id', `notices`.`notice` as 'notice', IF( CHAR_LENGTH(`schools1`.`name`), CONCAT_WS('', `schools1`.`name`), '') as 'school', IF( CHAR_LENGTH(`departments1`.`name`), CONCAT_WS('', `departments1`.`name`), '') as 'department', `notices`.`year_of_study` as 'year_of_study', if(`notices`.`date`,date_format(`notices`.`date`,'%m/%d/%Y'),'') as 'date'"
148 );
149
150 if(isset($sql_fields[$table_name])){
151 return $sql_fields[$table_name];
152 }
153
154 return false;
155 }
156
157 #########################################################
158
159 function get_sql_from($table_name, $skip_permissions = false){
160 $sql_from = array(
161 'schools' => "`schools` ",
162 'departments' => "`departments` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`departments`.`school` ",
163 'class_time_table' => "`class_time_table` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`class_time_table`.`school` LEFT JOIN `departments` as departments1 ON `departments1`.`id`=`class_time_table`.`department` ",
164 'exam_time_table' => "`exam_time_table` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`exam_time_table`.`school` LEFT JOIN `departments` as departments1 ON `departments1`.`id`=`exam_time_table`.`department` ",
165 'personal_time_table' => "`personal_time_table` ",
166 'student_details' => "`student_details` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`student_details`.`school` LEFT JOIN `departments` as departments1 ON `departments1`.`id`=`student_details`.`department` ",
167 'notices' => "`notices` LEFT JOIN `schools` as schools1 ON `schools1`.`id`=`notices`.`school` LEFT JOIN `departments` as departments1 ON `departments1`.`id`=`notices`.`department` "
168 );
169
170 $pkey = array(
171 'schools' => 'id',
172 'departments' => 'id',
173 'class_time_table' => 'id',
174 'exam_time_table' => 'id',
175 'personal_time_table' => 'id',
176 'student_details' => 'id',
177 'notices' => 'id'
178 );
179
180 if(isset($sql_from[$table_name])){
181 if($skip_permissions) return $sql_from[$table_name];
182
183 // mm: build the query based on current member's permissions
184 $perm = getTablePermissions($table_name);
185 if($perm[2] == 1){ // view owner only
186 $sql_from[$table_name] .= ", membership_userrecords WHERE `{$table_name}`.`{$pkey[$table_name]}`=membership_userrecords.pkValue and membership_userrecords.tableName='{$table_name}' and lcase(membership_userrecords.memberID)='" . getLoggedMemberID() . "'";
187 }elseif($perm[2] == 2){ // view group only
188 $sql_from[$table_name] .= ", membership_userrecords WHERE `{$table_name}`.`{$pkey[$table_name]}`=membership_userrecords.pkValue and membership_userrecords.tableName='{$table_name}' and membership_userrecords.groupID='" . getLoggedGroupID() . "'";
189 }elseif($perm[2] == 3){ // view all
190 $sql_from[$table_name] .= ' WHERE 1=1';
191 }else{ // view none
192 return false;
193 }
194 return $sql_from[$table_name];
195 }
196
197 return false;
198 }
199
200 #########################################################
201
202 function get_joined_record($table, $id, $skip_permissions = false){
203 $sql_fields = get_sql_fields($table);
204 $sql_from = get_sql_from($table, $skip_permissions);
205
206 if(!$sql_fields || !$sql_from) return false;
207
208 $pk = getPKFieldName($table);
209 if(!$pk) return false;
210
211 $safe_id = makeSafe($id, false);
212 $sql = "SELECT {$sql_fields} FROM {$sql_from} AND `{$table}`.`{$pk}`='{$safe_id}'";
213 $eo['silentErrors'] = true;
214 $res = sql($sql, $eo);
215 if($row = db_fetch_assoc($res)) return $row;
216
217 return false;
218 }
219
220 #########################################################
221
222 function get_defaults($table){
223 /* array of tables and their fields, with default values (or empty), excluding automatic values */
224 $defaults = array(
225 'schools' => array(
226 'id' => '',
227 'name' => ''
228 ),
229 'departments' => array(
230 'id' => '',
231 'name' => '',
232 'school' => ''
233 ),
234 'class_time_table' => array(
235 'id' => '',
236 'day' => '',
237 'time_start' => '',
238 'time_end' => '',
239 'unit_code' => '',
240 'venue' => '',
241 'school' => '',
242 'department' => '',
243 'year_of_study' => ''
244 ),
245 'exam_time_table' => array(
246 'id' => '',
247 'date' => '1',
248 'time_start' => '',
249 'time_end' => '',
250 'unit_code' => '',
251 'venue' => '',
252 'school' => '',
253 'department' => '',
254 'year_of_study' => ''
255 ),
256 'personal_time_table' => array(
257 'id' => '',
258 'day' => '',
259 'time_start' => '',
260 'time_end' => '',
261 'activity' => ''
262 ),
263 'student_details' => array(
264 'id' => '',
265 'full_name' => '',
266 'school' => '',
267 'department' => '',
268 'year_of_study' => '',
269 'reg_no' => ''
270 ),
271 'notices' => array(
272 'id' => '',
273 'notice' => '',
274 'school' => '',
275 'department' => '',
276 'year_of_study' => '',
277 'date' => ''
278 )
279 );
280
281 return isset($defaults[$table]) ? $defaults[$table] : array();
282 }
283
284 #########################################################
285
286 function logInMember(){
287 $redir = 'index.php';
288 if($_POST['signIn'] != ''){
289 if($_POST['username'] != '' && $_POST['password'] != ''){
290 $username = makeSafe(strtolower($_POST['username']));
291 $password = md5($_POST['password']);
292
293 if(sqlValue("select count(1) from membership_users where lcase(memberID)='$username' and passMD5='$password' and isApproved=1 and isBanned=0")==1){
294 $_SESSION['memberID']=$username;
295 $_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
296 if($_POST['rememberMe']==1){
297 @setcookie('Jisort_rememberMe', md5($username.$password), time()+86400*30);
298 }else{
299 @setcookie('Jisort_rememberMe', '', time()-86400*30);
300 }
301
302 // hook: login_ok
303 if(function_exists('login_ok')){
304 $args=array();
305 if(!$redir=login_ok(getMemberInfo(), $args)){
306 $redir='index.php';
307 }
308 }
309
310 redirect($redir);
311 exit;
312 }
313 }
314
315 // hook: login_failed
316 if(function_exists('login_failed')){
317 $args=array();
318 login_failed(array(
319 'username' => $_POST['username'],
320 'password' => $_POST['password'],
321 'IP' => $_SERVER['REMOTE_ADDR']
322 ), $args);
323 }
324
325 if(!headers_sent()) header('HTTP/1.0 403 Forbidden');
326 redirect("index.php?loginFailed=1");
327 exit;
328 }elseif((!$_SESSION['memberID'] || $_SESSION['memberID']==$adminConfig['anonymousMember']) && $_COOKIE['Jisort_rememberMe']!=''){
329 $chk=makeSafe($_COOKIE['Jisort_rememberMe']);
330 if($username=sqlValue("select memberID from membership_users where convert(md5(concat(memberID, passMD5)), char)='$chk' and isBanned=0")){
331 $_SESSION['memberID']=$username;
332 $_SESSION['memberGroupID']=sqlValue("select groupID from membership_users where lcase(memberID)='$username'");
333 }
334 }
335 }
336
337 #########################################################
338
339 function htmlUserBar(){
340 global $adminConfig, $Translation;
341 if(!defined('PREPEND_PATH')) define('PREPEND_PATH', '');
342
343 ob_start();
344 $home_page = (basename($_SERVER['PHP_SELF'])=='index.php' ? true : false);
345
346 ?>
347 <!-- <nav class="navbar navbar-default navbar-fixed-top hidden-print" role="navigation"> -->
348 <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top" role="navigation">
349 <!-- application title is obtained from the name besides the yellow database icon in AppGini, use underscores for spaces -->
350 <a class="navbar-brand" href="<?php echo PREPEND_PATH; ?>index.php"><i class="glyphicon glyphicon-home"></i> Hệ thống xếp lịch học tín chỉ cho sinh viên CNTT</a>
351 <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
352 <span class="sr-only">Toggle navigation</span>
353 <span class="icon-bar"></span>
354 <span class="icon-bar"></span>
355 <span class="icon-bar"></span>
356 </button>
357 <div class="collapse navbar-collapse" id="navbarResponsive">
358 <ul class="navbar-nav navbar-sidenav codefly" id="exampleAccordion">
359 <?php if(!$home_page){ ?>
360 <?php echo NavMenus(); ?>
361 <?php } ?>
362 </ul>
363
364 <?php if(getLoggedAdmin()){ ?>
365 <ul class="nav navbar-nav">
366 <a href="<?php echo PREPEND_PATH; ?>admin/pageHome.php" class="btn btn-danger navbar-btn hidden-xs" title="<?php echo html_attr($Translation['admin area']); ?>"><i class="glyphicon glyphicon-cog"></i> <?php echo $Translation['admin area']; ?></a>
367 <a href="<?php echo PREPEND_PATH; ?>admin/pageHome.php" class="btn btn-danger navbar-btn visible-xs btn-lg" title="<?php echo html_attr($Translation['admin area']); ?>"><i class="glyphicon glyphicon-cog"></i> <?php echo $Translation['admin area']; ?></a>
368 </ul>
369 <?php } ?>
370
371 <?php if(!$_GET['signIn'] && !$_GET['loginFailed']){ ?>
372 <?php if(getLoggedMemberID() == $adminConfig['anonymousMember']){ ?>
373 <p class="navbar-text navbar-right"> </p>
374 <a href="<?php echo PREPEND_PATH; ?>index.php?signIn=1" class="btn btn-success navbar-btn navbar-right"><?php echo $Translation['sign in']; ?></a>
375 <p class="navbar-text navbar-right">
376 <?php echo $Translation['not signed in']; ?>
377 </p>
378 <?php }else{ ?>
379 <ul class="nav navbar-nav navbar-right hidden-xs" style="min-width: 330px;">
380 <a class="btn navbar-btn btn-default" href="<?php echo PREPEND_PATH; ?>index.php?signOut=1"><i class="glyphicon glyphicon-log-out"></i> <?php echo $Translation['sign out']; ?></a>
381 <p class="navbar-text">
382 <?php echo $Translation['signed as']; ?> <strong><a href="<?php echo PREPEND_PATH; ?>membership_profile.php" class="navbar-link"><?php echo getLoggedMemberID(); ?></a></strong>
383 </p>
384 </ul>
385 <ul class="nav navbar-nav visible-xs">
386 <a class="btn navbar-btn btn-default btn-lg visible-xs" href="<?php echo PREPEND_PATH; ?>index.php?signOut=1"><i class="glyphicon glyphicon-log-out"></i> <?php echo $Translation['sign out']; ?></a>
387 <p class="navbar-text text-center">
388 <?php echo $Translation['signed as']; ?> <strong><a href="<?php echo PREPEND_PATH; ?>membership_profile.php" class="navbar-link"><?php echo getLoggedMemberID(); ?></a></strong>
389 </p>
390 </ul>
391 <script>
392 /* periodically check if user is still signed in */
393 setInterval(function(){
394 $j.ajax({
395 url: '<?php echo PREPEND_PATH; ?>ajax_check_login.php',
396 success: function(username){
397 if(!username.length) window.location = '<?php echo PREPEND_PATH; ?>index.php?signIn=1';
398 }
399 });
400 }, 60000);
401 </script>
402 <?php } ?>
403 <?php } ?>
404 </div>
405 </nav>
406 <?php
407
408 $html = ob_get_contents();
409 ob_end_clean();
410
411 return $html;
412 }
413
414 #########################################################
415
416 function showNotifications($msg = '', $class = '', $fadeout = true){
417 global $Translation;
418
419 $notify_template_no_fadeout = '<div id="%%ID%%" class="alert alert-dismissable %%CLASS%%" style="display: none; padding-top: 6px; padding-bottom: 6px;">' .
420 '<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>' .
421 '%%MSG%%</div>' .
422 '<script> jQuery(function(){ /* */ jQuery("#%%ID%%").show("slow"); }); </script>'."\n";
423 $notify_template = '<div id="%%ID%%" class="alert %%CLASS%%" style="display: none; padding-top: 6px; padding-bottom: 6px;">%%MSG%%</div>' .
424 '<script>' .
425 'jQuery(function(){' .
426 'jQuery("#%%ID%%").show("slow", function(){' .
427 'setTimeout(function(){ /* */ jQuery("#%%ID%%").hide("slow"); }, 4000);' .
428 '});' .
429 '});' .
430 '</script>'."\n";
431
432 if(!$msg){ // if no msg, use url to detect message to display
433 if($_REQUEST['record-added-ok'] != ''){
434 $msg = $Translation['new record saved'];
435 $class = 'alert-success';
436 }elseif($_REQUEST['record-added-error'] != ''){
437 $msg = $_SESSION['custom_alert'];
438 unset($_SESSION['custom_alert']);
439 $class = 'alert-danger';
440 $fadeout = false;
441 }elseif($_REQUEST['record-updated-ok'] != ''){
442 $msg = $Translation['record updated'];
443 $class = 'alert-success';
444 }elseif($_REQUEST['record-updated-error'] != ''){
445 $msg = $Translation['Couldn\'t save changes to the record'];
446 $class = 'alert-danger';
447 $fadeout = false;
448 }elseif($_REQUEST['record-deleted-ok'] != ''){
449 $msg = $Translation['The record has been deleted successfully'];
450 $class = 'alert-success';
451 $fadeout = false;
452 }elseif($_REQUEST['record-deleted-error'] != ''){
453 $msg = $Translation['Couldn\'t delete this record'];
454 $class = 'alert-danger';
455 $fadeout = false;
456 }else{
457 return '';
458 }
459 }
460 $id = 'notification-' . rand();
461
462 $out = ($fadeout ? $notify_template : $notify_template_no_fadeout);
463 $out = str_replace('%%ID%%', $id, $out);
464 $out = str_replace('%%MSG%%', $msg, $out);
465 $out = str_replace('%%CLASS%%', $class, $out);
466
467 return $out;
468 }
469
470 #########################################################
471
472 function parseMySQLDate($date, $altDate){
473 // is $date valid?
474 if(preg_match("/^\d{4}-\d{1,2}-\d{1,2}$/", trim($date))){
475 return trim($date);
476 }
477
478 if($date != '--' && preg_match("/^\d{4}-\d{1,2}-\d{1,2}$/", trim($altDate))){
479 return trim($altDate);
480 }
481
482 if($date != '--' && $altDate && intval($altDate)==$altDate){
483 return @date('Y-m-d', @time() + ($altDate >= 1 ? $altDate - 1 : $altDate) * 86400);
484 }
485
486 return '';
487 }
488
489 #########################################################
490
491 function parseCode($code, $isInsert=true, $rawData=false){
492 if($isInsert){
493 $arrCodes=array(
494 '<%%creatorusername%%>' => $_SESSION['memberID'],
495 '<%%creatorgroupid%%>' => $_SESSION['memberGroupID'],
496 '<%%creatorip%%>' => $_SERVER['REMOTE_ADDR'],
497 '<%%creatorgroup%%>' => sqlValue("select name from membership_groups where groupID='{$_SESSION['memberGroupID']}'"),
498
499 '<%%creationdate%%>' => ($rawData ? @date('Y-m-d') : @date('n/j/Y')),
500 '<%%creationtime%%>' => ($rawData ? @date('H:i:s') : @date('h:i:s a')),
501 '<%%creationdatetime%%>' => ($rawData ? @date('Y-m-d H:i:s') : @date('n/j/Y h:i:s a')),
502 '<%%creationtimestamp%%>' => ($rawData ? @date('Y-m-d H:i:s') : @time())
503 );
504 }else{
505 $arrCodes=array(
506 '<%%editorusername%%>' => $_SESSION['memberID'],
507 '<%%editorgroupid%%>' => $_SESSION['memberGroupID'],
508 '<%%editorip%%>' => $_SERVER['REMOTE_ADDR'],
509 '<%%editorgroup%%>' => sqlValue("select name from membership_groups where groupID='{$_SESSION['memberGroupID']}'"),
510
511 '<%%editingdate%%>' => ($rawData ? @date('Y-m-d') : @date('n/j/Y')),
512 '<%%editingtime%%>' => ($rawData ? @date('H:i:s') : @date('h:i:s a')),
513 '<%%editingdatetime%%>' => ($rawData ? @date('Y-m-d H:i:s') : @date('n/j/Y h:i:s a')),
514 '<%%editingtimestamp%%>' => ($rawData ? @date('Y-m-d H:i:s') : @time())
515 );
516 }
517
518 $pc=str_ireplace(array_keys($arrCodes), array_values($arrCodes), $code);
519
520 return $pc;
521 }
522
523 #########################################################
524
525 function addFilter($index, $filterAnd, $filterField, $filterOperator, $filterValue){
526 // validate input
527 if($index < 1 || $index > 80 || !is_int($index)) return false;
528 if($filterAnd != 'or') $filterAnd = 'and';
529 $filterField = intval($filterField);
530
531 /* backward compatibility */
532 if(in_array($filterOperator, $GLOBALS['filter_operators'])){
533 $filterOperator = array_search($filterOperator, $GLOBALS['filter_operators']);
534 }
535
536 if(!in_array($filterOperator, array_keys($GLOBALS['filter_operators']))){
537 $filterOperator = 'like';
538 }
539
540 if(!$filterField){
541 $filterOperator = '';
542 $filterValue = '';
543 }
544
545 $_REQUEST['FilterAnd'][$index] = $filterAnd;
546 $_REQUEST['FilterField'][$index] = $filterField;
547 $_REQUEST['FilterOperator'][$index] = $filterOperator;
548 $_REQUEST['FilterValue'][$index] = $filterValue;
549
550 return true;
551 }
552
553 #########################################################
554
555 function clearFilters(){
556 for($i=1; $i<=80; $i++){
557 addFilter($i, '', 0, '', '');
558 }
559 }
560
561 #########################################################
562
563 if(!function_exists('str_ireplace')){
564 function str_ireplace($search, $replace, $subject){
565 $ret=$subject;
566 if(is_array($search)){
567 for($i=0; $i<count($search); $i++){
568 $ret=str_ireplace($search[$i], $replace[$i], $ret);
569 }
570 }else{
571 $ret=preg_replace('/'.preg_quote($search, '/').'/i', $replace, $ret);
572 }
573
574 return $ret;
575 }
576 }
577
578 #########################################################
579
580 /**
581 * Loads a given view from the templates folder, passing the given data to it
582 * @param $view the name of a php file (without extension) to be loaded from the 'templates' folder
583 * @param $the_data_to_pass_to_the_view (optional) associative array containing the data to pass to the view
584 * @return the output of the parsed view as a string
585 */
586 function loadView($view, $the_data_to_pass_to_the_view=false){
587 global $Translation;
588
589 $view = dirname(__FILE__)."/templates/$view.php";
590 if(!is_file($view)) return false;
591
592 if(is_array($the_data_to_pass_to_the_view)){
593 foreach($the_data_to_pass_to_the_view as $k => $v)
594 $$k = $v;
595 }
596 unset($the_data_to_pass_to_the_view, $k, $v);
597
598 ob_start();
599 @include($view);
600 $out=ob_get_contents();
601 ob_end_clean();
602
603 return $out;
604 }
605
606 #########################################################
607
608 /**
609 * Loads a table template from the templates folder, passing the given data to it
610 * @param $table_name the name of the table whose template is to be loaded from the 'templates' folder
611 * @param $the_data_to_pass_to_the_table associative array containing the data to pass to the table template
612 * @return the output of the parsed table template as a string
613 */
614 function loadTable($table_name, $the_data_to_pass_to_the_table = array()){
615 $dont_load_header = $the_data_to_pass_to_the_table['dont_load_header'];
616 $dont_load_footer = $the_data_to_pass_to_the_table['dont_load_footer'];
617
618 $header = $table = $footer = '';
619
620 if(!$dont_load_header){
621 // try to load tablename-header
622 if(!($header = loadView("{$table_name}-header", $the_data_to_pass_to_the_table))){
623 $header = loadView('table-common-header', $the_data_to_pass_to_the_table);
624 }
625 }
626
627 $table = loadView($table_name, $the_data_to_pass_to_the_table);
628
629 if(!$dont_load_footer){
630 // try to load tablename-footer
631 if(!($footer = loadView("{$table_name}-footer", $the_data_to_pass_to_the_table))){
632 $footer = loadView('table-common-footer', $the_data_to_pass_to_the_table);
633 }
634 }
635
636 return "{$header}{$table}{$footer}";
637 }
638
639 #########################################################
640
641 function filterDropdownBy($filterable, $filterers, $parentFilterers, $parentPKField, $parentCaption, $parentTable, &$filterableCombo){
642 $filterersArray = explode(',', $filterers);
643 $parentFilterersArray = explode(',', $parentFilterers);
644 $parentFiltererList = '`' . implode('`, `', $parentFilterersArray) . '`';
645 $res=sql("SELECT `$parentPKField`, $parentCaption, $parentFiltererList FROM `$parentTable` ORDER BY 2", $eo);
646 $filterableData = array();
647 while($row=db_fetch_row($res)){
648 $filterableData[$row[0]] = $row[1];
649 $filtererIndex = 0;
650 foreach($filterersArray as $filterer){
651 $filterableDataByFilterer[$filterer][$row[$filtererIndex + 2]][$row[0]] = $row[1];
652 $filtererIndex++;
653 }
654 $row[0] = addslashes($row[0]);
655 $row[1] = addslashes($row[1]);
656 $jsonFilterableData .= "\"{$row[0]}\":\"{$row[1]}\",";
657 }
658 $jsonFilterableData .= '}';
659 $jsonFilterableData = '{'.str_replace(',}', '}', $jsonFilterableData);
660 $filterJS = "\nvar {$filterable}_data = $jsonFilterableData;";
661
662 foreach($filterersArray as $filterer){
663 if(is_array($filterableDataByFilterer[$filterer])) foreach($filterableDataByFilterer[$filterer] as $filtererItem => $filterableItem){
664 $jsonFilterableDataByFilterer[$filterer] .= '"'.addslashes($filtererItem).'":{';
665 foreach($filterableItem as $filterableItemID => $filterableItemData){
666 $jsonFilterableDataByFilterer[$filterer] .= '"'.addslashes($filterableItemID).'":"'.addslashes($filterableItemData).'",';
667 }
668 $jsonFilterableDataByFilterer[$filterer] .= '},';
669 }
670 $jsonFilterableDataByFilterer[$filterer] .= '}';
671 $jsonFilterableDataByFilterer[$filterer] = '{'.str_replace(',}', '}', $jsonFilterableDataByFilterer[$filterer]);
672
673 $filterJS.="\n\n// code for filtering {$filterable} by {$filterer}\n";
674 $filterJS.="\nvar {$filterable}_data_by_{$filterer} = {$jsonFilterableDataByFilterer[$filterer]}; ";
675 $filterJS.="\nvar selected_{$filterable} = \$j('#{$filterable}').val();";
676 $filterJS.="\nvar {$filterable}_change_by_{$filterer} = function(){";
677 $filterJS.="\n\t$('{$filterable}').options.length=0;";
678 $filterJS.="\n\t$('{$filterable}').options[0] = new Option();";
679 $filterJS.="\n\tif(\$j('#{$filterer}').val()){";
680 $filterJS.="\n\t\tfor({$filterable}_item in {$filterable}_data_by_{$filterer}[\$j('#{$filterer}').val()]){";
681 $filterJS.="\n\t\t\t$('{$filterable}').options[$('{$filterable}').options.length] = new Option(";
682 $filterJS.="\n\t\t\t\t{$filterable}_data_by_{$filterer}[\$j('#{$filterer}').val()][{$filterable}_item],";
683 $filterJS.="\n\t\t\t\t{$filterable}_item,";
684 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false),";
685 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false)";
686 $filterJS.="\n\t\t\t);";
687 $filterJS.="\n\t\t}";
688 $filterJS.="\n\t}else{";
689 $filterJS.="\n\t\tfor({$filterable}_item in {$filterable}_data){";
690 $filterJS.="\n\t\t\t$('{$filterable}').options[$('{$filterable}').options.length] = new Option(";
691 $filterJS.="\n\t\t\t\t{$filterable}_data[{$filterable}_item],";
692 $filterJS.="\n\t\t\t\t{$filterable}_item,";
693 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false),";
694 $filterJS.="\n\t\t\t\t({$filterable}_item == selected_{$filterable} ? true : false)";
695 $filterJS.="\n\t\t\t);";
696 $filterJS.="\n\t\t}";
697 $filterJS.="\n\t\tif(selected_{$filterable} && selected_{$filterable} == \$j('#{$filterable}').val()){";
698 $filterJS.="\n\t\t\tfor({$filterer}_item in {$filterable}_data_by_{$filterer}){";
699 $filterJS.="\n\t\t\t\tfor({$filterable}_item in {$filterable}_data_by_{$filterer}[{$filterer}_item]){";
700 $filterJS.="\n\t\t\t\t\tif({$filterable}_item == selected_{$filterable}){";
701 $filterJS.="\n\t\t\t\t\t\t$('{$filterer}').value = {$filterer}_item;";
702 $filterJS.="\n\t\t\t\t\t\tbreak;";
703 $filterJS.="\n\t\t\t\t\t}";
704 $filterJS.="\n\t\t\t\t}";
705 $filterJS.="\n\t\t\t\tif({$filterable}_item == selected_{$filterable}) break;";
706 $filterJS.="\n\t\t\t}";
707 $filterJS.="\n\t\t}";
708 $filterJS.="\n\t}";
709 $filterJS.="\n\t$('{$filterable}').highlight();";
710 $filterJS.="\n};";
711 $filterJS.="\n$('{$filterer}').observe('change', function(){ /* */ window.setTimeout({$filterable}_change_by_{$filterer}, 25); });";
712 $filterJS.="\n";
713 }
714
715 $filterableCombo = new Combo;
716 $filterableCombo->ListType = 0;
717 $filterableCombo->ListItem = array_slice(array_values($filterableData), 0, 10);
718 $filterableCombo->ListData = array_slice(array_keys($filterableData), 0, 10);
719 $filterableCombo->SelectName = $filterable;
720 $filterableCombo->AllowNull = true;
721
722 return $filterJS;
723 }
724
725 #########################################################
726 function br2nl($text){
727 return preg_replace('/\<br(\s*)?\/?\>/i', "\n", $text);
728 }
729
730 #########################################################
731
732 if(!function_exists('htmlspecialchars_decode')){
733 function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT){
734 return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
735 }
736 }
737
738 #########################################################
739
740 function entitiesToUTF8($input){
741 return preg_replace_callback('/(&#[0-9]+;)/', '_toUTF8', $input);
742 }
743
744 function _toUTF8($m){
745 if(function_exists('mb_convert_encoding')){
746 return mb_convert_encoding($m[1], "UTF-8", "HTML-ENTITIES");
747 }else{
748 return $m[1];
749 }
750 }
751
752 #########################################################
753
754 function func_get_args_byref() {
755 if(!function_exists('debug_backtrace')) return false;
756
757 $trace = debug_backtrace();
758 return $trace[1]['args'];
759 }
760
761 #########################################################
762
763 function permissions_sql($table, $level = 'all'){
764 if(!in_array($level, array('user', 'group'))){ $level = 'all'; }
765 $perm = getTablePermissions($table);
766 $from = '';
767 $where = '';
768 $pk = getPKFieldName($table);
769
770 if($perm[2] == 1 || ($perm[2] > 1 && $level == 'user')){ // view owner only
771 $from = 'membership_userrecords';
772 $where = "(`$table`.`$pk`=membership_userrecords.pkValue and membership_userrecords.tableName='$table' and lcase(membership_userrecords.memberID)='".getLoggedMemberID()."')";
773 }elseif($perm[2] == 2 || ($perm[2] > 2 && $level == 'group')){ // view group only
774 $from = 'membership_userrecords';
775 $where = "(`$table`.`$pk`=membership_userrecords.pkValue and membership_userrecords.tableName='$table' and membership_userrecords.groupID='".getLoggedGroupID()."')";
776 }elseif($perm[2] == 3){ // view all
777 // no further action
778 }elseif($perm[2] == 0){ // view none
779 return false;
780 }
781
782 return array('where' => $where, 'from' => $from, 0 => $where, 1 => $from);
783 }
784
785 #########################################################
786
787 function error_message($msg, $back_url = '', $full_page = true){
788 $curr_dir = dirname(__FILE__);
789 global $Translation;
790
791 ob_start();
792
793 if($full_page) include_once($curr_dir . '/header.php');
794
795 echo '<div class="panel panel-danger">';
796 echo '<div class="panel-heading"><h3 class="panel-title">' . $Translation['error:'] . '</h3></div>';
797 echo '<div class="panel-body"><p class="text-danger">' . $msg . '</p>';
798 if($back_url !== false){ // explicitly passing false suppresses the back link completely
799 echo '<div class="text-center">';
800 if($back_url){
801 echo '<a href="' . $back_url . '" class="btn btn-danger btn-lg vspacer-lg"><i class="glyphicon glyphicon-chevron-left"></i> ' . $Translation['< back'] . '</a>';
802 }else{
803 echo '<a href="#" class="btn btn-danger btn-lg vspacer-lg" onclick="history.go(-1); return false;"><i class="glyphicon glyphicon-chevron-left"></i> ' . $Translation['< back'] . '</a>';
804 }
805 echo '</div>';
806 }
807 echo '</div>';
808 echo '</div>';
809
810 if($full_page) include_once($curr_dir . '/footer.php');
811
812 $out = ob_get_contents();
813 ob_end_clean();
814
815 return $out;
816 }
817
818 #########################################################
819
820 function toMySQLDate($formattedDate, $sep = datalist_date_separator, $ord = datalist_date_format){
821 // extract date elements
822 $de=explode($sep, $formattedDate);
823 $mySQLDate=intval($de[strpos($ord, 'Y')]).'-'.intval($de[strpos($ord, 'm')]).'-'.intval($de[strpos($ord, 'd')]);
824 return $mySQLDate;
825 }
826
827 #########################################################
828
829 function reIndex(&$arr){
830 $i=1;
831 foreach($arr as $n=>$v){
832 $arr2[$i]=$n;
833 $i++;
834 }
835 return $arr2;
836 }
837
838 #########################################################
839
840 function get_embed($provider, $url, $max_width = '', $max_height = '', $retrieve = 'html'){
841 global $Translation;
842 if(!$url) return '';
843
844 $providers = array(
845 'youtube' => array('oembed' => 'http://www.youtube.com/oembed?'),
846 'googlemap' => array('oembed' => '', 'regex' => '/^http.*\.google\..*maps/i')
847 );
848
849 if(!isset($providers[$provider])){
850 return '<div class="text-danger">' . $Translation['invalid provider'] . '</div>';
851 }
852
853 if(isset($providers[$provider]['regex']) && !preg_match($providers[$provider]['regex'], $url)){
854 return '<div class="text-danger">' . $Translation['invalid url'] . '</div>';
855 }
856
857 if($providers[$provider]['oembed']){
858 $oembed = $providers[$provider]['oembed'] . 'url=' . urlencode($url) . "&maxwidth={$max_width}&maxheight={$max_height}&format=json";
859 $data_json = request_cache($oembed);
860
861 $data = json_decode($data_json, true);
862 if($data === null){
863 /* an error was returned rather than a json string */
864 if($retrieve == 'html') return "<div class=\"text-danger\">{$data_json}\n<!-- {$oembed} --></div>";
865 return '';
866 }
867
868 return (isset($data[$retrieve]) ? $data[$retrieve] : $data['html']);
869 }
870
871 /* special cases (where there is no oEmbed provider) */
872 if($provider == 'googlemap') return get_embed_googlemap($url, $max_width, $max_height, $retrieve);
873
874 return '<div class="text-danger">Invalid provider!</div>';
875 }
876
877 #########################################################
878
879 function get_embed_googlemap($url, $max_width = '', $max_height = '', $retrieve = 'html'){
880 global $Translation;
881 $url_parts = parse_url($url);
882 $coords_regex = '/-?\d+(\.\d+)?[,+]-?\d+(\.\d+)?(,\d{1,2}z)?/'; /* https://stackoverflow.com/questions/2660201 */
883
884 if(preg_match($coords_regex, $url_parts['path'] . '?' . $url_parts['query'], $m)){
885 list($lat, $long, $zoom) = explode(',', $m[0]);
886 $zoom = intval($zoom);
887 if(!$zoom) $zoom = 10; /* default zoom */
888 if(!$max_height) $max_height = 360;
889 if(!$max_width) $max_width = 480;
890
891 $api_key = '';
892 $embed_url = "https://www.google.com/maps/embed/v1/view?key={$api_key}¢er={$lat},{$long}&zoom={$zoom}&maptype=roadmap";
893 $thumbnail_url = "https://maps.googleapis.com/maps/api/staticmap?key={$api_key}¢er={$lat},{$long}&zoom={$zoom}&maptype=roadmap&size={$max_width}x{$max_height}";
894
895 if($retrieve == 'html'){
896 return "<iframe width=\"{$max_width}\" height=\"{$max_height}\" frameborder=\"0\" style=\"border:0\" src=\"{$embed_url}\"></iframe>";
897 }else{
898 return $thumbnail_url;
899 }
900 }else{
901 return '<div class="text-danger">' . $Translation['cant retrieve coordinates from url'] . '</div>';
902 }
903 }
904
905 #########################################################
906
907 function request_cache($request, $force_fetch = false){
908 $max_cache_lifetime = 7 * 86400; /* max cache lifetime in seconds before refreshing from source */
909
910 /* membership_cache table exists? if not, create it */
911 static $cache_table_exists = false;
912 if(!$cache_table_exists && !$force_fetch){
913 $te = sqlValue("show tables like 'membership_cache'");
914 if(!$te){
915 if(!sql("CREATE TABLE `membership_cache` (`request` VARCHAR(100) NOT NULL, `request_ts` INT, `response` TEXT NOT NULL, PRIMARY KEY (`request`))", $eo)){
916 /* table can't be created, so force fetching request */
917 return request_cache($request, true);
918 }
919 }
920 $cache_table_exists = true;
921 }
922
923 /* retrieve response from cache if exists */
924 if(!$force_fetch){
925 $res = sql("select response, request_ts from membership_cache where request='" . md5($request) . "'", $eo);
926 if(!$row = db_fetch_array($res)) return request_cache($request, true);
927
928 $response = $row[0];
929 $response_ts = $row[1];
930 if($response_ts < time() - $max_cache_lifetime) return request_cache($request, true);
931 }
932
933 /* if no response in cache, issue a request */
934 if(!$response || $force_fetch){
935 $response = @file_get_contents($request);
936 if($response === false){
937 $error = error_get_last();
938 $error_message = preg_replace('/.*: (.*)/', '$1', $error['message']);
939 return $error_message;
940 }elseif($cache_table_exists){
941 /* store response in cache */
942 $ts = time();
943 sql("replace into membership_cache set request='" . md5($request) . "', request_ts='{$ts}', response='" . makeSafe($response, false) . "'", $eo);
944 }
945 }
946
947 return $response;
948 }
949
950 #########################################################
951
952 function check_record_permission($table, $id, $perm = 'view'){
953 if($perm != 'edit' && $perm != 'delete') $perm = 'view';
954
955 $perms = getTablePermissions($table);
956 if(!$perms[$perm]) return false;
957
958 $safe_id = makeSafe($id);
959 $safe_table = makeSafe($table);
960
961 if($perms[$perm] == 1){ // own records only
962 $username = getLoggedMemberID();
963 $owner = sqlValue("select memberID from membership_userrecords where tableName='{$safe_table}' and pkValue='{$safe_id}'");
964 if($owner == $username) return true;
965 }elseif($perms[$perm] == 2){ // group records
966 $group_id = getLoggedGroupID();
967 $owner_group_id = sqlValue("select groupID from membership_userrecords where tableName='{$safe_table}' and pkValue='{$safe_id}'");
968 if($owner_group_id == $group_id) return true;
969 }elseif($perms[$perm] == 3){ // all records
970 return true;
971 }
972
973 return false;
974 }
975
976 #########################################################
977
978 function NavMenus($options = array()){
979 if(!defined('PREPEND_PATH')) define('PREPEND_PATH', '');
980 global $Translation;
981 $prepend_path = PREPEND_PATH;
982
983 /* default options */
984 if(empty($options)){
985 $options = array(
986 'tabs' => 7
987 );
988 }
989
990 $table_group_name = array_keys(get_table_groups()); /* 0 => group1, 1 => group2 .. */
991 /* if only one group named 'None', set to translation of 'select a table' */
992 if((count($table_group_name) == 1 && $table_group_name[0] == 'None') || count($table_group_name) < 1) $table_group_name[0] = $Translation['select a table'];
993 $table_group_index = array_flip($table_group_name); /* group1 => 0, group2 => 1 .. */
994 $menu = array_fill(0, count($table_group_name), '');
995
996 $t = time();
997 $arrTables = getTableList();
998 if(is_array($arrTables)){
999 foreach($arrTables as $tn => $tc){
1000 /* ---- list of tables where hide link in nav menu is set ---- */
1001 $tChkHL = array_search($tn, array());
1002
1003 /* ---- list of tables where filter first is set ---- */
1004 $tChkFF = array_search($tn, array());
1005 if($tChkFF !== false && $tChkFF !== null){
1006 $searchFirst = '&Filter_x=1';
1007 }else{
1008 $searchFirst = '';
1009 }
1010
1011 /* when no groups defined, $table_group_index['None'] is NULL, so $menu_index is still set to 0 */
1012 $menu_index = intval($table_group_index[$tc[3]]);
1013 if(!$tChkHL && $tChkHL !== 0) $menu[$menu_index] .= "<li class=\"nav-item\"><a href=\"{$prepend_path}{$tn}_view.php?t={$t}{$searchFirst}\"><img src=\"{$prepend_path}" . ($tc[2] ? $tc[2] : 'blank.gif') . "\" height=\"32\"> {$tc[0]}</a></li>";
1014 }
1015 }
1016
1017 // custom nav links, as defined in "hooks/links-navmenu.php"
1018 global $navLinks;
1019 if(is_array($navLinks)){
1020 $memberInfo = getMemberInfo();
1021 $links_added = array();
1022 foreach($navLinks as $link){
1023 if(!isset($link['url']) || !isset($link['title'])) continue;
1024 if($memberInfo['admin'] || @in_array($memberInfo['group'], $link['groups']) || @in_array('*', $link['groups'])){
1025 $menu_index = intval($link['table_group']);
1026 if(!$links_added[$menu_index]) $menu[$menu_index] .= '<li class="divider"></li>';
1027
1028 /* add prepend_path to custom links if they aren't absolute links */
1029 if(!preg_match('/^(http|\/\/)/i', $link['url'])) $link['url'] = $prepend_path . $link['url'];
1030 if(!preg_match('/^(http|\/\/)/i', $link['icon']) && $link['icon']) $link['icon'] = $prepend_path . $link['icon'];
1031
1032 $menu[$menu_index] .= "<li class=\"nav-item\"><a href=\"{$link['url']}\"><img src=\"" . ($link['icon'] ? $link['icon'] : "{$prepend_path}blank.gif") . "\" height=\"32\"> {$link['title']}</a></li>";
1033 $links_added[$menu_index]++;
1034 }
1035 }
1036 }
1037
1038 $menu_wrapper = '';
1039 for($i = 0; $i < count($menu); $i++){
1040 $menu_wrapper .= <<<EOT
1041 {$menu[$i]}
1042 <!--<li class="dropdown">-->
1043 <a href="#" class="dropdown-toggle" data-toggle="dropdown">{$table_group_name[$i]} <b class="caret"></b></a>
1044 <!-- <ul class="dropdown-menu" role="menu">{$menu[$i]}</ul> -->
1045 <!--</li>-->
1046 EOT;
1047 }
1048
1049 return $menu_wrapper;
1050 }
1051
1052 #########################################################
1053
1054 function StyleSheet(){
1055 if(!defined('PREPEND_PATH')) define('PREPEND_PATH', '');
1056 $prepend_path = PREPEND_PATH;
1057
1058 $css_links = <<<EOT
1059
1060 <link rel="stylesheet" href="{$prepend_path}resources/initializr/css/bootstrap.css">
1061 <link rel="stylesheet" href="{$prepend_path}resources/lightbox/css/lightbox.css" media="screen">
1062 <link rel="stylesheet" href="{$prepend_path}resources/select2/select2.css" media="screen">
1063 <link rel="stylesheet" href="{$prepend_path}resources/timepicker/bootstrap-timepicker.min.css" media="screen">
1064 <link rel="stylesheet" href="{$prepend_path}dynamic.css.php">
1065 EOT;
1066
1067 return $css_links;
1068 }
1069
1070 #########################################################
1071
1072 function getUploadDir($dir){
1073 global $Translation;
1074
1075 if($dir==""){
1076 $dir=$Translation['ImageFolder'];
1077 }
1078
1079 if(substr($dir, -1)!="/"){
1080 $dir.="/";
1081 }
1082
1083 return $dir;
1084 }
1085
1086 #########################################################
1087
1088 function PrepareUploadedFile($FieldName, $MaxSize, $FileTypes = 'jpg|jpeg|gif|png', $NoRename = false, $dir = ''){
1089 global $Translation;
1090 $f = $_FILES[$FieldName];
1091 if($f['error'] == 4 || !$f['name']) return '';
1092
1093 $dir = getUploadDir($dir);
1094
1095 /* get php.ini upload_max_filesize in bytes */
1096 $php_upload_size_limit = trim(ini_get('upload_max_filesize'));
1097 $last = strtolower($php_upload_size_limit[strlen($php_upload_size_limit) - 1]);
1098 switch($last){
1099 case 'g':
1100 $php_upload_size_limit *= 1024;
1101 case 'm':
1102 $php_upload_size_limit *= 1024;
1103 case 'k':
1104 $php_upload_size_limit *= 1024;
1105 }
1106
1107 $MaxSize = min($MaxSize, $php_upload_size_limit);
1108
1109 if($f['size'] > $MaxSize || $f['error']){
1110 echo error_message(str_replace('<MaxSize>', intval($MaxSize / 1024), $Translation['file too large']));
1111 exit;
1112 }
1113 if(!preg_match('/\.(' . $FileTypes . ')$/i', $f['name'], $ft)){
1114 echo error_message(str_replace('<FileTypes>', str_replace('|', ', ', $FileTypes), $Translation['invalid file type']));
1115 exit;
1116 }
1117
1118 $name = str_replace(' ', '_', $f['name']);
1119 if(!$NoRename) $name = substr(md5(microtime() . rand(0, 100000)), -17) . $ft[0];
1120
1121 if(!file_exists($dir)) @mkdir($dir, 0777);
1122
1123 if(!@move_uploaded_file($f['tmp_name'], $dir . $name)){
1124 echo error_message("Couldn't save the uploaded file. Try chmoding the upload folder '{$dir}' to 777.");
1125 exit;
1126 }
1127
1128 @chmod($dir . $name, 0666);
1129 return $name;
1130 }
1131
1132 #########################################################
1133
1134 function get_home_links($homeLinks, $default_classes, $tgroup = ''){
1135 if(!is_array($homeLinks) || !count($homeLinks)) return '';
1136
1137 $memberInfo = getMemberInfo();
1138
1139 ob_start();
1140 foreach($homeLinks as $link){
1141 if(!isset($link['url']) || !isset($link['title'])) continue;
1142 if($tgroup != $link['table_group'] && $tgroup != '*') continue;
1143
1144 /* fall-back classes if none defined */
1145 if(!$link['grid_column_classes']) $link['grid_column_classes'] = $default_classes['grid_column'];
1146 if(!$link['panel_classes']) $link['panel_classes'] = $default_classes['panel'];
1147 if(!$link['link_classes']) $link['link_classes'] = $default_classes['link'];
1148
1149 if($memberInfo['admin'] || @in_array($memberInfo['group'], $link['groups']) || @in_array('*', $link['groups'])){
1150 ?>
1151 <div class="col-xs-12 <?php echo $link['grid_column_classes']; ?>">
1152 <div class="panel <?php echo $link['panel_classes']; ?>">
1153 <div class="panel-body">
1154 <a class="btn btn-block btn-lg <?php echo $link['link_classes']; ?>" title="<?php echo preg_replace("/&(#[0-9]+|[a-z]+);/i", "&$1;", html_attr(strip_tags($link['description']))); ?>" href="<?php echo $link['url']; ?>"><?php echo ($link['icon'] ? '<img src="' . $link['icon'] . '">' : ''); ?><strong><?php echo $link['title']; ?></strong></a>
1155 <div class="panel-body-description"><?php echo $link['description']; ?></div>
1156 </div>
1157 </div>
1158 </div>
1159 <?php
1160 }
1161 }
1162
1163 $html = ob_get_contents();
1164 ob_end_clean();
1165
1166 return $html;
1167 }
1168
1169 #########################################################
1170
1171 function quick_search_html($search_term, $label, $separate_dv = true){
1172 global $Translation;
1173
1174 $safe_search = html_attr($search_term);
1175 $safe_label = html_attr($label);
1176 $safe_clear_label = html_attr($Translation['Reset Filters']);
1177
1178 if($separate_dv){
1179 $reset_selection = "document.myform.SelectedID.value = '';";
1180 }else{
1181 $reset_selection = "document.myform.writeAttribute('novalidate', 'novalidate');";
1182 }
1183 $reset_selection .= ' document.myform.NoDV.value=1; return true;';
1184
1185 $html = <<<EOT
1186 <div class="input-group" id="quick-search">
1187 <input type="text" id="SearchString" name="SearchString" value="{$safe_search}" class="form-control" placeholder="{$safe_label}">
1188 <span class="input-group-btn">
1189 <button name="Search_x" value="1" id="Search" type="submit" onClick="{$reset_selection}" class="btn btn-default" title="{$safe_label}"><i class="glyphicon glyphicon-search"></i></button>
1190 <button name="ClearQuickSearch" value="1" id="ClearQuickSearch" type="submit" onClick="\$j('#SearchString').val(''); {$reset_selection}" class="btn btn-default" title="{$safe_clear_label}"><i class="glyphicon glyphicon-remove-circle"></i></button>
1191 </span>
1192 </div>
1193 EOT;
1194 return $html;
1195 }
1196
1197 #########################################################